thunderhub/server/schema/auth/resolvers.ts

124 lines
3.2 KiB
TypeScript
Raw Normal View History

import getConfig from 'next/config';
import jwt from 'jsonwebtoken';
2020-07-16 00:08:46 +02:00
import {
readCookie,
refreshCookie,
PRE_PASS_STRING,
} from 'server/helpers/fileHelpers';
import { ContextType } from 'server/types/apiTypes';
import { logger } from 'server/helpers/logger';
import cookie from 'cookie';
import { requestLimiter } from 'server/helpers/rateLimiter';
2020-07-15 12:14:16 +02:00
import bcrypt from 'bcryptjs';
import { appConstants } from 'server/utils/appConstants';
const { serverRuntimeConfig } = getConfig() || {};
const { cookiePath, nodeEnv } = serverRuntimeConfig || {};
export const authResolvers = {
Query: {
2020-08-05 23:44:05 +02:00
getAuthToken: async (
_: undefined,
params: any,
context: ContextType
): Promise<boolean> => {
const { ip, secret, sso, res } = context;
await requestLimiter(ip, 'getAuthToken');
if (!sso) {
logger.warn('No SSO account available');
2020-08-05 23:44:05 +02:00
return false;
}
if (!sso.socket || !sso.macaroon) {
logger.warn('Host and macaroon are required for SSO');
2020-08-05 23:44:05 +02:00
return false;
}
if (!params.cookie) {
2020-08-05 23:44:05 +02:00
return false;
}
if (cookiePath === '') {
logger.warn('SSO auth not available since no cookie path was provided');
2020-08-05 23:44:05 +02:00
return false;
}
const cookieFile = readCookie(cookiePath);
2020-06-11 07:50:49 +02:00
if (
(cookieFile && cookieFile.trim() === params.cookie.trim()) ||
2020-06-11 07:50:49 +02:00
nodeEnv === 'development'
) {
refreshCookie(cookiePath);
const token = jwt.sign({ id: 'sso' }, secret);
res.setHeader(
'Set-Cookie',
cookie.serialize(appConstants.cookieName, token, {
httpOnly: true,
sameSite: true,
path: '/',
})
);
return true;
}
2020-06-11 07:50:49 +02:00
logger.debug(`Cookie ${params.cookie} different to file ${cookieFile}`);
2020-08-05 23:44:05 +02:00
return false;
},
getSessionToken: async (
_: undefined,
params: any,
context: ContextType
) => {
const { ip, secret, res } = context;
await requestLimiter(ip, 'getSessionToken');
const account = context.accounts.find(a => a.id === params.id) || null;
if (!account) {
logger.debug(`Account ${params.id} not found`);
return null;
}
2020-07-16 00:08:46 +02:00
const cleanPassword = account.password.replace(PRE_PASS_STRING, '');
const isPassword = bcrypt.compareSync(params.password, cleanPassword);
2020-07-15 12:14:16 +02:00
if (!isPassword) {
throw new Error('WrongPasswordForLogin');
}
2020-07-15 12:14:16 +02:00
logger.debug(`Correct password for account ${params.id}`);
const token = jwt.sign({ id: params.id }, secret);
2020-07-15 12:14:16 +02:00
res.setHeader(
'Set-Cookie',
cookie.serialize(appConstants.cookieName, token, {
2020-07-15 12:14:16 +02:00
httpOnly: true,
sameSite: true,
path: '/',
2020-07-15 12:14:16 +02:00
})
);
return true;
},
},
Mutation: {
2020-08-25 08:47:43 +02:00
logout: async (_: undefined, __: any, context: ContextType) => {
const { ip, res } = context;
await requestLimiter(ip, 'logout');
res.setHeader(
'Set-Cookie',
2020-08-25 08:47:43 +02:00
cookie.serialize(appConstants.cookieName, '', {
maxAge: -1,
httpOnly: true,
sameSite: true,
path: '/',
})
);
return true;
},
},
};