FoundKey/packages/backend/src/server/api/authenticate.ts
Johann150 d1ec058d5c
All checks were successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/lint-foundkey-js Pipeline was successful
ci/woodpecker/push/lint-client Pipeline was successful
ci/woodpecker/push/lint-backend Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
server: refactor Cache to hold fetcher as attribute
Instead of having to pass the fetcher every time you want to fetch
something, the fetcher is stored in an attribute of the Cache.
2022-11-13 19:39:30 +01:00

85 lines
2.3 KiB
TypeScript

import { CacheableLocalUser, ILocalUser } from '@/models/entities/user.js';
import { Users, AccessTokens, Apps } from '@/models/index.js';
import { AccessToken } from '@/models/entities/access-token.js';
import { Cache } from '@/misc/cache.js';
import { App } from '@/models/entities/app.js';
import { userByIdCache, localUserByNativeTokenCache } from '@/services/user-cache.js';
import isNativeToken from './common/is-native-token.js';
const appCache = new Cache<App>(
Infinity,
(id) => Apps.findOneByOrFail({ id }),
);
export class AuthenticationError extends Error {
constructor(message: string) {
super(message);
this.name = 'AuthenticationError';
}
}
export default async (authorization: string | null | undefined, bodyToken: string | null | undefined): Promise<[CacheableLocalUser | 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];
if (accessToken.appId) {
const app = await appCache.fetch(accessToken.appId);
return [user, {
id: accessToken.id,
permission: app.permission,
} as AccessToken];
} else {
return [user, accessToken];
}
}
};