forked from FoundKeyGang/FoundKey
70 lines
2 KiB
TypeScript
70 lines
2 KiB
TypeScript
import { ILocalUser } from '@/models/entities/user.js';
|
|
import { Users, AccessTokens } from '@/models/index.js';
|
|
import { AccessToken } from '@/models/entities/access-token.js';
|
|
import { userByIdCache, localUserByNativeTokenCache } from '@/services/user-cache.js';
|
|
import isNativeToken from './common/is-native-token.js';
|
|
|
|
export class AuthenticationError extends Error {
|
|
constructor(message: string) {
|
|
super(message);
|
|
this.name = 'AuthenticationError';
|
|
}
|
|
}
|
|
|
|
export async function authenticate(authorization: string | null | undefined, bodyToken: string | null | undefined): Promise<[ILocalUser | null | undefined, AccessToken | null | undefined]> {
|
|
let maybeToken: string | null = null;
|
|
|
|
// check if there is an authorization header set
|
|
if (authorization != null) {
|
|
if (bodyToken != null) {
|
|
throw new AuthenticationError('using multiple authorization schemes');
|
|
}
|
|
|
|
// check if OAuth 2.0 Bearer tokens are being used
|
|
// Authorization schemes are case insensitive
|
|
if (authorization.substring(0, 7).toLowerCase() === 'bearer ') {
|
|
maybeToken = authorization.substring(7);
|
|
} else {
|
|
throw new AuthenticationError('unsupported authentication scheme');
|
|
}
|
|
} else if (bodyToken != null) {
|
|
maybeToken = bodyToken;
|
|
} else {
|
|
return [null, null];
|
|
}
|
|
const token: string = maybeToken;
|
|
|
|
if (isNativeToken(token)) {
|
|
const user = await localUserByNativeTokenCache.fetch(token);
|
|
|
|
if (user == null) {
|
|
throw new AuthenticationError('unknown token');
|
|
}
|
|
|
|
return [user, null];
|
|
} else {
|
|
const accessToken = await AccessTokens.findOne({
|
|
where: [{
|
|
hash: token.toLowerCase(), // app
|
|
}, {
|
|
token, // miauth
|
|
}],
|
|
});
|
|
|
|
if (accessToken == null) {
|
|
throw new AuthenticationError('unknown token');
|
|
}
|
|
|
|
AccessTokens.update(accessToken.id, {
|
|
lastUsedAt: new Date(),
|
|
});
|
|
|
|
const user = await userByIdCache.fetch(accessToken.userId);
|
|
|
|
// can't authorize remote users
|
|
if (!Users.isLocalUser(user)) return [null, null];
|
|
|
|
return [user, accessToken];
|
|
}
|
|
}
|