summaryrefslogtreecommitdiff
path: root/packages/backend/src/server
diff options
context:
space:
mode:
authorHazelnoot <acomputerdog@gmail.com>2025-05-06 23:19:23 -0400
committerHazelnoot <acomputerdog@gmail.com>2025-05-08 11:23:20 -0400
commitb2ea03383cd53ac213c4dee6dbd086ab6f54daa7 (patch)
treed2fd601cb1c24d3e290aa4cef53c6d6df99953c2 /packages/backend/src/server
parentfix "cannot use 'in' operator" error (diff)
downloadsharkey-b2ea03383cd53ac213c4dee6dbd086ab6f54daa7.tar.gz
sharkey-b2ea03383cd53ac213c4dee6dbd086ab6f54daa7.tar.bz2
sharkey-b2ea03383cd53ac213c4dee6dbd086ab6f54daa7.zip
implement '/v1/apps/verify_credentials'
Diffstat (limited to 'packages/backend/src/server')
-rw-r--r--packages/backend/src/server/api/AuthenticateService.ts2
-rw-r--r--packages/backend/src/server/api/endpoint-list.ts1
-rw-r--r--packages/backend/src/server/api/endpoints/app/current.ts73
-rw-r--r--packages/backend/src/server/api/mastodon/MastodonConverters.ts12
-rw-r--r--packages/backend/src/server/api/mastodon/endpoints/apps.ts9
5 files changed, 95 insertions, 2 deletions
diff --git a/packages/backend/src/server/api/AuthenticateService.ts b/packages/backend/src/server/api/AuthenticateService.ts
index 601618553e..397626c49d 100644
--- a/packages/backend/src/server/api/AuthenticateService.ts
+++ b/packages/backend/src/server/api/AuthenticateService.ts
@@ -84,6 +84,8 @@ export class AuthenticateService implements OnApplicationShutdown {
return [user, {
id: accessToken.id,
permission: app.permission,
+ appId: app.id,
+ app,
} as MiAccessToken];
} else {
return [user, accessToken];
diff --git a/packages/backend/src/server/api/endpoint-list.ts b/packages/backend/src/server/api/endpoint-list.ts
index 1c5a781fd9..a78c3e9ae6 100644
--- a/packages/backend/src/server/api/endpoint-list.ts
+++ b/packages/backend/src/server/api/endpoint-list.ts
@@ -128,6 +128,7 @@ export * as 'antennas/update' from './endpoints/antennas/update.js';
export * as 'ap/get' from './endpoints/ap/get.js';
export * as 'ap/show' from './endpoints/ap/show.js';
export * as 'app/create' from './endpoints/app/create.js';
+export * as 'app/current' from './endpoints/app/current.js';
export * as 'app/show' from './endpoints/app/show.js';
export * as 'auth/accept' from './endpoints/auth/accept.js';
export * as 'auth/session/generate' from './endpoints/auth/session/generate.js';
diff --git a/packages/backend/src/server/api/endpoints/app/current.ts b/packages/backend/src/server/api/endpoints/app/current.ts
new file mode 100644
index 0000000000..39b5ef347c
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/app/current.ts
@@ -0,0 +1,73 @@
+/*
+ * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import type { AppsRepository } from '@/models/_.js';
+import { AppEntityService } from '@/core/entities/AppEntityService.js';
+import { DI } from '@/di-symbols.js';
+import { ApiError } from '../../error.js';
+
+export const meta = {
+ tags: ['app'],
+
+ errors: {
+ credentialRequired: {
+ message: 'Credential required.',
+ code: 'CREDENTIAL_REQUIRED',
+ id: '1384574d-a912-4b81-8601-c7b1c4085df1',
+ httpStatusCode: 401,
+ },
+ noAppLogin: {
+ message: 'Not logged in with an app.',
+ code: 'NO_APP_LOGIN',
+ id: '339a4ad2-48c3-47fc-bd9d-2408f05120f8',
+ },
+ },
+
+ res: {
+ type: 'object',
+ optional: false, nullable: false,
+ ref: 'App',
+ },
+
+ // 10 calls per 5 seconds
+ limit: {
+ duration: 1000 * 5,
+ max: 10,
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {},
+ required: [],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+ constructor(
+ @Inject(DI.appsRepository)
+ private appsRepository: AppsRepository,
+
+ private appEntityService: AppEntityService,
+ ) {
+ super(meta, paramDef, async (_, user, token) => {
+ if (!user) {
+ throw new ApiError(meta.errors.credentialRequired);
+ }
+ if (!token || !token.appId) {
+ throw new ApiError(meta.errors.noAppLogin);
+ }
+
+ const app = token.app ?? await this.appsRepository.findOneByOrFail({ id: token.appId });
+
+ return await this.appEntityService.pack(app, user, {
+ detail: true,
+ includeSecret: false,
+ });
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/mastodon/MastodonConverters.ts b/packages/backend/src/server/api/mastodon/MastodonConverters.ts
index cf625d6e94..375ea1ef08 100644
--- a/packages/backend/src/server/api/mastodon/MastodonConverters.ts
+++ b/packages/backend/src/server/api/mastodon/MastodonConverters.ts
@@ -4,7 +4,7 @@
*/
import { Inject, Injectable } from '@nestjs/common';
-import { Entity, MastodonEntity } from 'megalodon';
+import { Entity, MastodonEntity, MisskeyEntity } from 'megalodon';
import mfm from '@transfem-org/sfm-js';
import { MastodonNotificationType } from 'megalodon/lib/src/mastodon/notification.js';
import { NotificationType } from 'megalodon/lib/src/notification.js';
@@ -369,6 +369,15 @@ export class MastodonConverters {
type: convertNotificationType(notification.type as NotificationType),
};
}
+
+ public convertApplication(app: MisskeyEntity.App): MastodonEntity.Application {
+ return {
+ name: app.name,
+ scopes: app.permission,
+ redirect_uri: app.callbackUrl,
+ redirect_uris: [app.callbackUrl],
+ };
+ }
}
function simpleConvert<T>(data: T): T {
@@ -459,4 +468,3 @@ export function convertRelationship(relationship: Partial<Entity.Relationship> &
note: relationship.note ?? '',
};
}
-
diff --git a/packages/backend/src/server/api/mastodon/endpoints/apps.ts b/packages/backend/src/server/api/mastodon/endpoints/apps.ts
index 5fce838f47..72b520c74a 100644
--- a/packages/backend/src/server/api/mastodon/endpoints/apps.ts
+++ b/packages/backend/src/server/api/mastodon/endpoints/apps.ts
@@ -5,6 +5,7 @@
import { Injectable } from '@nestjs/common';
import { MastodonClientService } from '@/server/api/mastodon/MastodonClientService.js';
+import { MastodonConverters } from '@/server/api/mastodon/MastodonConverters.js';
import type { FastifyInstance } from 'fastify';
const readScope = [
@@ -59,6 +60,7 @@ type AuthMastodonRoute = { Body?: AuthPayload, Querystring: AuthPayload };
export class ApiAppsMastodon {
constructor(
private readonly clientService: MastodonClientService,
+ private readonly mastoConverters: MastodonConverters,
) {}
public register(fastify: FastifyInstance): void {
@@ -108,6 +110,13 @@ export class ApiAppsMastodon {
return reply.send(response);
});
+
+ fastify.get('/v1/apps/verify_credentials', async (_request, reply) => {
+ const client = this.clientService.getClient(_request);
+ const data = await client.verifyAppCredentials();
+ const response = this.mastoConverters.convertApplication(data.data);
+ return reply.send(response);
+ });
}
}