This commit is contained in:
tamaina 2023-06-04 16:41:45 +00:00
parent f651ca4b48
commit 35b1f73b51
9 changed files with 149 additions and 151 deletions

View file

@ -6,6 +6,7 @@ import type { AuthSession } from '@/models/entities/AuthSession.js';
import type { User } from '@/models/entities/User.js';
import { AppEntityService } from './AppEntityService.js';
import { bindThis } from '@/decorators.js';
import { Packed } from 'misskey-js';
@Injectable()
export class AuthSessionEntityService {
@ -21,7 +22,7 @@ export class AuthSessionEntityService {
public async pack(
src: AuthSession['id'] | AuthSession,
me?: { id: User['id'] } | null | undefined,
) {
): Promise<Packed<'AuthSession'>> {
const session = typeof src === 'object' ? src : await this.authSessionsRepository.findOneByOrFail({ id: src });
return await awaitAll({

View file

@ -7,47 +7,10 @@ import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';
export const meta = {
tags: ['auth'],
requireCredential: false,
res: {
type: 'object',
optional: false, nullable: false,
properties: {
token: {
type: 'string',
optional: false, nullable: false,
},
url: {
type: 'string',
optional: false, nullable: false,
format: 'url',
},
},
},
errors: {
noSuchApp: {
message: 'No such app.',
code: 'NO_SUCH_APP',
id: '92f93e63-428e-4f2f-a5a4-39e1407fe998',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
appSecret: { type: 'string' },
},
required: ['appSecret'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'auth/session/genrate'> {
name = 'auth/session/genrate' as const;
constructor(
@Inject(DI.config)
private config: Config,
@ -60,14 +23,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private idService: IdService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
// Lookup app
const app = await this.appsRepository.findOneBy({
secret: ps.appSecret,
});
if (app == null) {
throw new ApiError(meta.errors.noSuchApp);
throw new ApiError(this.meta.errors.noSuchApp);
}
// Generate token

View file

@ -5,66 +5,24 @@ import { AuthSessionEntityService } from '@/core/entities/AuthSessionEntityServi
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';
export const meta = {
tags: ['auth'],
requireCredential: false,
errors: {
noSuchSession: {
message: 'No such session.',
code: 'NO_SUCH_SESSION',
id: 'bd72c97d-eba7-4adb-a467-f171b8847250',
},
},
res: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
app: {
type: 'object',
optional: false, nullable: false,
ref: 'App',
},
token: {
type: 'string',
optional: false, nullable: false,
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
token: { type: 'string' },
},
required: ['token'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'auth/session/show'> {
name = 'auth/session/show' as const;
constructor(
@Inject(DI.authSessionsRepository)
private authSessionsRepository: AuthSessionsRepository,
private authSessionEntityService: AuthSessionEntityService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
// Lookup session
const session = await this.authSessionsRepository.findOneBy({
token: ps.token,
});
if (session == null) {
throw new ApiError(meta.errors.noSuchSession);
throw new ApiError(this.meta.errors.noSuchSession);
}
return await this.authSessionEntityService.pack(session, me);

View file

@ -5,61 +5,10 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';
export const meta = {
tags: ['auth'],
requireCredential: false,
res: {
type: 'object',
optional: false, nullable: false,
properties: {
accessToken: {
type: 'string',
optional: false, nullable: false,
},
user: {
type: 'object',
optional: false, nullable: false,
ref: 'UserDetailedNotMe',
},
},
},
errors: {
noSuchApp: {
message: 'No such app.',
code: 'NO_SUCH_APP',
id: 'fcab192a-2c5a-43b7-8ad8-9b7054d8d40d',
},
noSuchSession: {
message: 'No such session.',
code: 'NO_SUCH_SESSION',
id: '5b5a1503-8bc8-4bd0-8054-dc189e8cdcb3',
},
pendingSession: {
message: 'This session is not completed yet.',
code: 'PENDING_SESSION',
id: '8c8a4145-02cc-4cca-8e66-29ba60445a8e',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
appSecret: { type: 'string' },
token: { type: 'string' },
},
required: ['appSecret', 'token'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'auth/session/userkey'> {
name = 'auth/session/userkey' as const;
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@ -75,14 +24,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private userEntityService: UserEntityService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
// Lookup app
const app = await this.appsRepository.findOneBy({
secret: ps.appSecret,
});
if (app == null) {
throw new ApiError(meta.errors.noSuchApp);
throw new ApiError(this.meta.errors.noSuchApp);
}
// Fetch token
@ -92,11 +41,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
});
if (session == null) {
throw new ApiError(meta.errors.noSuchSession);
throw new ApiError(this.meta.errors.noSuchSession);
}
if (session.userId == null) {
throw new ApiError(meta.errors.pendingSession);
throw new ApiError(this.meta.errors.pendingSession);
}
// Lookup access token

View file

@ -2341,7 +2341,113 @@ export const endpoints = {
$ref: 'https://misskey-hub.net/api/schemas/App',
},
}],
},
//#endregion
//#region auth
'auth/session/genrate': {
tags: ['auth'],
requireCredential: false,
errors: {
noSuchApp: {
message: 'No such app.',
code: 'NO_SUCH_APP',
id: '92f93e63-428e-4f2f-a5a4-39e1407fe998',
},
},
defines: [{
req: {
type: 'object',
properties: {
appSecret: { type: 'string' },
},
required: ['appSecret'],
},
res: {
type: 'object',
properties: {
token: { type: 'string' },
url: { type: 'string', format: 'url' },
},
required: ['token', 'url'],
},
}],
},
'auth/session/show': {
tags: ['auth'],
requireCredential: false,
errors: {
noSuchSession: {
message: 'No such session.',
code: 'NO_SUCH_SESSION',
id: 'bd72c97d-eba7-4adb-a467-f171b8847250',
},
},
defines: [{
req: {
type: 'object',
properties: {
token: { type: 'string' },
},
required: ['token'],
},
res: {
$ref: 'https://misskey-hub.net/api/schemas/AuthSession',
},
}],
},
'auth/session/userkey': {
tags: ['auth'],
requireCredential: false,
errors: {
noSuchApp: {
message: 'No such app.',
code: 'NO_SUCH_APP',
id: 'fcab192a-2c5a-43b7-8ad8-9b7054d8d40d',
},
noSuchSession: {
message: 'No such session.',
code: 'NO_SUCH_SESSION',
id: '5b5a1503-8bc8-4bd0-8054-dc189e8cdcb3',
},
pendingSession: {
message: 'This session is not completed yet.',
code: 'PENDING_SESSION',
id: '8c8a4145-02cc-4cca-8e66-29ba60445a8e',
},
},
defines: [{
req: {
type: 'object',
properties: {
appSecret: { type: 'string' },
token: { type: 'string' },
},
required: ['appSecret', 'token'],
},
res: {
type: 'object',
properties: {
accessToken: { type: 'string' },
user: {
$ref: 'https://misskey-hub.net/api/schemas/UserDetailedNotMe',
}
},
required: ['accessToken', 'user'],
}
}],
},
//#endregion
} as const satisfies { [x: string]: IEndpointMeta; };

View file

@ -119,11 +119,7 @@ export type Stats = {
driveUsageRemote: number;
};
export type AuthSession = {
id: ID;
app: App;
token: string;
};
export type AuthSession = Serialized<Packed<'AuthSession'>>;
export type FollowRequest = {
id: ID;

View file

@ -56,6 +56,7 @@ import {
SignInSchema,
} from './schemas/sign-in.js';
import { packedModerationLogSchema } from './schemas/moderation-log.js';
import { packedAuthSessionSchema } from './schemas/auth-session.js';
import { Error, ApiError } from './schemas/error.js';
import type { JSONSchema7, JSONSchema7Definition, GetDef, GetRefs, GetKeys, UnionToArray } from 'schema-type';
@ -109,6 +110,7 @@ export const refs = {
ServerInfoAdmin: ServerInfoAdminSchema,
ModerationLog: packedModerationLogSchema,
SignIn: SignInSchema,
AuthSession: packedAuthSessionSchema,
Error: Error,
ApiError: ApiError,

View file

@ -0,0 +1,19 @@
import type { JSONSchema7Definition } from 'schema-type';
export const packedAuthSessionSchema = {
$id: 'https://misskey-hub.net/api/schemas/AuthSession',
type: 'object',
properties: {
id: { $ref: 'https://misskey-hub.net/api/schemas/Id' },
app: { $ref: 'https://misskey-hub.net/api/schemas/App' },
token: {
type: 'string',
},
},
required: [
'id',
'app',
'token',
],
} as const satisfies JSONSchema7Definition;

View file

@ -1,3 +1,4 @@
import { test } from 'node:test';
import { Packed, Def } from '../src/schemas';
import { expectType } from 'tsd';
@ -122,6 +123,9 @@ describe('schemas', () => {
test('moderation log', () => {
type ModerationLog = Packed<'ModerationLog'>;
});
test('auth session', () => {
type AuthSession = Packed<'AuthSession'>;
});
test('error', () => {
type Error = Packed<'Error'>;
type ApiError = Packed<'ApiError'>;