Release 1.0.6 #4

Merged
mifi merged 12 commits from develop into main 2023-05-26 21:49:26 +00:00
36 changed files with 482 additions and 553 deletions
Showing only changes of commit 35b89062e4 - Show all commits

19
.eslintrc.js Normal file
View File

@@ -0,0 +1,19 @@
/* eslint-env node */
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:import/errors',
'plugin:prettier/recommended',
'prettier',
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
settings: {
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx'],
},
'import/resolver': 'typescript',
},
root: true,
};

View File

@@ -1,8 +1,9 @@
.build.yarnrc.yml
.drone.yml
.prettierrc
.yarnrc.yml
babel.config.*
jest.config.*
src
tsconfig.json
tslint.json
.prettierrc
.yarnrc.yml
.drone.yml
babel.config.*
jest.config.*

7
.prettierrc.js Normal file
View File

@@ -0,0 +1,7 @@
module.exports = {
parser: 'typescript',
printWidth: 120,
trailingComma: 'all',
tabWidth: 4,
singleQuote: true,
};

View File

@@ -1,6 +1,6 @@
import { Auth, Log } from "..";
import { Action } from "../constants/action";
import { getLoginToken } from "../utils/getLoginToken";
import { Auth, Log } from '..';
import { Action } from '../constants/action';
import { getLoginToken } from '../utils/getLoginToken';
export const authenticate = async (username: string, password: string) => {
const doc = await Auth.findByUsername(username).catch();

View File

@@ -1,5 +1,5 @@
import { StringSchemaDefinition } from "mongoose";
import { Auth, Strategy } from "..";
import { StringSchemaDefinition } from 'mongoose';
import { Auth, Strategy } from '..';
export const deleteStrategy = async (id: StringSchemaDefinition) => {
const strategy = await Strategy.findById(id);

View File

@@ -1,7 +1,7 @@
import { readOneByUsername } from "../dao/readOneByUsername";
import { Log, Token } from "..";
import { TokenType } from "../constants/tokens";
import { Action } from "../constants/action";
import { readOneByUsername } from '../dao/readOneByUsername';
import { Log, Token } from '..';
import { TokenType } from '../constants/tokens';
import { Action } from '../constants/action';
export const resetPasswordGet = async (username: string) => {
const doc = await readOneByUsername(username);

View File

@@ -1,11 +1,11 @@
import { Types } from "mongoose";
import { Types } from 'mongoose';
import { Log, Strategy, Token } from "..";
import { STRATEGIES } from "../constants/strategies";
import { AuthDocument } from "../schema/auth";
import { getLoginToken } from "../utils/getLoginToken";
import { StrategyDocument } from "../schema/strategy";
import { Action } from "../constants/action";
import { Log, Strategy, Token } from '..';
import { STRATEGIES } from '../constants/strategies';
import { AuthDocument } from '../schema/auth';
import { getLoginToken } from '../utils/getLoginToken';
import { StrategyDocument } from '../schema/strategy';
import { Action } from '../constants/action';
export const resetPasswordPost = async (token: string, password: string) => {
const parentId = await Token.validateResetToken(token);

View File

@@ -1,9 +1,9 @@
export enum Action {
AUTHENTICATE = "AUTHENTICATE",
AUTHENTICATE_FAILURE = "AUTHENTICATE_FAILURE",
CREATE = "CREATE",
DELETE = "DELETE",
RESET = "RESET",
RESET_REQUEST = "RESET_REQUEST",
UPDATE = "UPDATE",
AUTHENTICATE = 'AUTHENTICATE',
AUTHENTICATE_FAILURE = 'AUTHENTICATE_FAILURE',
CREATE = 'CREATE',
DELETE = 'DELETE',
RESET = 'RESET',
RESET_REQUEST = 'RESET_REQUEST',
UPDATE = 'UPDATE',
}

View File

@@ -4,7 +4,7 @@ export const DB_USERNAME = process.env.DB_USERNAME;
export const DB_PASSWORD = process.env.DB_PASSWORD;
export const DB_NAME = process.env.DB_NAME;
export const COLL_AUTH = "Auth";
export const COLL_LOG = "Log";
export const COLL_STRATEGY = "Strategy";
export const COLL_TOKEN = "Token";
export const COLL_AUTH = 'Auth';
export const COLL_LOG = 'Log';
export const COLL_STRATEGY = 'Strategy';
export const COLL_TOKEN = 'Token';

View File

@@ -1,21 +1,20 @@
export const PACKAGE_NAME = "@mifi/auth";
export const PACKAGE_NAME = '@mifi/auth';
export const PORT = process.env.PORT || 9000;
export const SESSION_KEY = process.env.SESSION_KEY || "secret-key";
export const SESSION_KEY = process.env.SESSION_KEY || 'secret-key';
export const JWT_AUDIENCE = process.env.JWT_AUDIENCE || "mifi.dev";
export const JWT_AUDIENCE = process.env.JWT_AUDIENCE || 'mifi.dev';
export const JWT_ISSUER = process.env.JWT_ISSUER || PACKAGE_NAME;
export const JWT_SECRET = process.env.JWT_SECRET || "secret";
export const JWT_SECRET = process.env.JWT_SECRET || 'secret';
export const LOGIN_VALID_TIMEOUT = process.env.LOGIN_VALID_TIMEOUT || "12h"; // ###d|h|m
export const RESET_VALID_TIMEOUT = process.env.RESET_VALID_TIMEOUT || "15m"; // ###d|h|m
export const VERIFY_VALID_TIMEOUT = process.env.VERIFY_VALID_TIMEOUT || "60d"; // ###d|h|m
export const LOGIN_VALID_TIMEOUT = process.env.LOGIN_VALID_TIMEOUT || '12h'; // ###d|h|m
export const RESET_VALID_TIMEOUT = process.env.RESET_VALID_TIMEOUT || '15m'; // ###d|h|m
export const VERIFY_VALID_TIMEOUT = process.env.VERIFY_VALID_TIMEOUT || '60d'; // ###d|h|m
export const DEFAULT_TOKEN_DAYS = process.env.DEFAULT_TOKEN_DAYS || 365;
export const ROUTE_PREFIX = process.env.ROUTE_PREFIX || "/auth";
export const LOGIN_ROUTE = process.env.LOGIN_ROUTE || "/login";
export const RESET_ROUTE = process.env.RESET_ROUTE || "/reset";
export const VERIFICATION_ROUTE =
process.env.VERIFICATION_ROUTE || "/verification";
export const ROUTE_PREFIX = process.env.ROUTE_PREFIX || '/auth';
export const LOGIN_ROUTE = process.env.LOGIN_ROUTE || '/login';
export const RESET_ROUTE = process.env.RESET_ROUTE || '/reset';
export const VERIFICATION_ROUTE = process.env.VERIFICATION_ROUTE || '/verification';
export const REQUIRE_VERIFICATION = process.env.REQUIRE_VERIFICATION || true;

View File

@@ -1,10 +1,9 @@
export enum ErrorCodes {
RESET_REQUEST_DATA = "RESET_REQUEST_DATA",
RESET_REQUEST_DATA = 'RESET_REQUEST_DATA',
}
export const ErrorMessages = {
[ErrorCodes.RESET_REQUEST_DATA]:
"A valid username and password must be provided",
[ErrorCodes.RESET_REQUEST_DATA]: 'A valid username and password must be provided',
};
export const getErrorBody = (code: ErrorCodes) => ({

View File

@@ -1,4 +1,4 @@
export enum TokenType {
RESET = "RESET",
VERIFICATION = "VERIFICATION",
RESET = 'RESET',
VERIFICATION = 'VERIFICATION',
}

View File

@@ -1,25 +1,21 @@
import { DatabaseError } from "@mifi/services-common/lib/domain/errors/DatabaseError";
import { DatabaseError } from '@mifi/services-common/lib/domain/errors/DatabaseError';
import { Auth, Log, Strategy, Token } from "..";
import { Auth as AuthProps } from "../schema/auth";
import { STRATEGIES } from "../constants/strategies";
import { REQUIRE_VERIFICATION } from "../constants/env";
import { TokenType } from "../constants/tokens";
import { Status } from "../constants/auth";
import { Action } from "../constants/action";
import { Auth, Log, Strategy, Token } from '..';
import { Auth as AuthProps } from '../schema/auth';
import { STRATEGIES } from '../constants/strategies';
import { REQUIRE_VERIFICATION } from '../constants/env';
import { TokenType } from '../constants/tokens';
import { Status } from '../constants/auth';
import { Action } from '../constants/action';
export const create = async ({
record,
username,
password,
}: AuthProps & { password: string }) => {
export const create = async ({ record, username, password }: AuthProps & { password: string }) => {
const status = REQUIRE_VERIFICATION ? Status.UNVERIFIED : Status.ACTIVE;
const doc = await Auth.create({
record,
status,
username,
}).catch((err) => {
throw new DatabaseError("failed to create user", { err });
throw new DatabaseError('failed to create user', { err });
});
if (doc) {
const strategy = await Strategy.create({
@@ -27,7 +23,7 @@ export const create = async ({
key: password,
parent: doc._id,
}).catch((err) => {
throw new DatabaseError("failed to create strategy", { err });
throw new DatabaseError('failed to create strategy', { err });
});
if (strategy) {
doc.strategies.push(strategy._id);
@@ -35,13 +31,11 @@ export const create = async ({
Log.add(doc._id, Action.CREATE);
return {
doc,
token:
REQUIRE_VERIFICATION &&
(await Token.getToken(TokenType.VERIFICATION, doc._id)),
token: REQUIRE_VERIFICATION && (await Token.getToken(TokenType.VERIFICATION, doc._id)),
};
}
await doc.deleteOne((err) => {
throw new DatabaseError("failed to remove invalid auth record", {
throw new DatabaseError('failed to remove invalid auth record', {
err,
doc,
});

View File

@@ -1,8 +1,8 @@
import { StringSchemaDefinition } from "mongoose";
import { StringSchemaDefinition } from 'mongoose';
import { Auth, Log, Strategy, Token } from "..";
import { Status } from "../constants/auth";
import { Action } from "../constants/action";
import { Auth, Log, Strategy, Token } from '..';
import { Status } from '../constants/auth';
import { Action } from '../constants/action';
export const deleteById = async (id: StringSchemaDefinition) => {
if (

View File

@@ -1,11 +1,9 @@
import { FilterQuery } from "mongoose";
import { FilterQuery } from 'mongoose';
import { Auth } from "../model/auth";
import { Status } from "../constants/auth";
import { AuthDocument } from "../schema/auth";
import { Auth } from '../model/auth';
import { Status } from '../constants/auth';
import { AuthDocument } from '../schema/auth';
export const readAll = async (query: FilterQuery<AuthDocument> = {}) =>
Auth.find(query);
export const readAll = async (query: FilterQuery<AuthDocument> = {}) => Auth.find(query);
export const readAllActive = async () =>
readAll({ status: { $ne: Status.DELETED } });
export const readAllActive = async () => readAll({ status: { $ne: Status.DELETED } });

View File

@@ -1,5 +1,5 @@
import { Types } from "mongoose";
import { Types } from 'mongoose';
import { Auth } from "../model/auth";
import { Auth } from '../model/auth';
export const readOneById = async (id: Types.ObjectId) => Auth.findById(id);

View File

@@ -1,6 +1,5 @@
import { Types } from "mongoose";
import { Types } from 'mongoose';
import { Auth } from "../model/auth";
import { Auth } from '../model/auth';
export const readOneByRecord = async (record: Types.ObjectId) =>
Auth.findOne({ record });
export const readOneByRecord = async (record: Types.ObjectId) => Auth.findOne({ record });

View File

@@ -1,4 +1,3 @@
import { Auth } from "../model/auth";
import { Auth } from '../model/auth';
export const readOneByUsername = async (username: string) =>
Auth.findOne({ username });
export const readOneByUsername = async (username: string) => Auth.findOne({ username });

View File

@@ -1,26 +1,16 @@
import mongoose from "mongoose";
import mongoose from 'mongoose';
import {
DB_HOST,
DB_NAME,
DB_PASSWORD,
DB_PORT,
DB_USERNAME,
} from "./constants/db";
import { Auth } from "./model/auth";
import { Log } from "./model/log";
import { Strategy } from "./model/strategy";
import { Token } from "./model/token";
import { DB_HOST, DB_NAME, DB_PASSWORD, DB_PORT, DB_USERNAME } from './constants/db';
import { Auth } from './model/auth';
import { Log } from './model/log';
import { Strategy } from './model/strategy';
import { Token } from './model/token';
const connection = mongoose
.connect(
`mongodb://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}`
)
.then((c) =>
console.debug("Database connection established", { connection: c })
)
.connect(`mongodb://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}`)
.then((c) => console.debug('Database connection established', { connection: c }))
.catch((error) => {
console.error("Mongo connection failure", error);
console.error('Mongo connection failure', error);
process.exit(1);
});

View File

@@ -1,9 +1,6 @@
import mongoose from "mongoose";
import mongoose from 'mongoose';
import { AuthDocument, AuthModel, AuthSchema } from "../schema/auth";
import { COLL_AUTH } from "../constants/db";
import { AuthDocument, AuthModel, AuthSchema } from '../schema/auth';
import { COLL_AUTH } from '../constants/db';
export const Auth = mongoose.model<AuthDocument, AuthModel>(
COLL_AUTH,
AuthSchema
);
export const Auth = mongoose.model<AuthDocument, AuthModel>(COLL_AUTH, AuthSchema);

View File

@@ -1,6 +1,6 @@
import mongoose from "mongoose";
import mongoose from 'mongoose';
import { LogModel, Log as LogDocument, LogSchema } from "../schema/log";
import { COLL_LOG } from "../constants/db";
import { LogModel, Log as LogDocument, LogSchema } from '../schema/log';
import { COLL_LOG } from '../constants/db';
export const Log = mongoose.model<LogDocument, LogModel>(COLL_LOG, LogSchema);

View File

@@ -1,13 +1,6 @@
import mongoose from "mongoose";
import mongoose from 'mongoose';
import {
StrategyDocument,
StrategyModel,
StrategySchema,
} from "../schema/strategy";
import { COLL_STRATEGY } from "../constants/db";
import { StrategyDocument, StrategyModel, StrategySchema } from '../schema/strategy';
import { COLL_STRATEGY } from '../constants/db';
export const Strategy = mongoose.model<StrategyDocument, StrategyModel>(
COLL_STRATEGY,
StrategySchema
);
export const Strategy = mongoose.model<StrategyDocument, StrategyModel>(COLL_STRATEGY, StrategySchema);

View File

@@ -1,13 +1,6 @@
import mongoose from "mongoose";
import mongoose from 'mongoose';
import {
TokenModel,
Token as TokenDocument,
TokenSchema,
} from "../schema/token";
import { COLL_TOKEN } from "../constants/db";
import { TokenModel, Token as TokenDocument, TokenSchema } from '../schema/token';
import { COLL_TOKEN } from '../constants/db';
export const Token = mongoose.model<TokenDocument, TokenModel>(
COLL_TOKEN,
TokenSchema
);
export const Token = mongoose.model<TokenDocument, TokenModel>(COLL_TOKEN, TokenSchema);

View File

@@ -1,17 +1,10 @@
import {
Document,
InferSchemaType,
Model,
Schema,
StringSchemaDefinition,
Types,
} from "mongoose";
import { Document, InferSchemaType, Model, Schema, StringSchemaDefinition, Types } from 'mongoose';
import { Status } from "../constants/auth";
import { COLL_STRATEGY } from "../constants/db";
import { STRATEGIES } from "../constants/strategies";
import { StrategyDocument } from "./strategy";
import { verify } from "../utils/password";
import { Status } from '../constants/auth';
import { COLL_STRATEGY } from '../constants/db';
import { STRATEGIES } from '../constants/strategies';
import { StrategyDocument } from './strategy';
import { verify } from '../utils/password';
export interface Auth {
is2FA?: boolean;
@@ -56,28 +49,17 @@ export const AuthSchema = new Schema<AuthDocument, AuthModel>(
{
minimize: true,
timestamps: true,
}
},
);
AuthSchema.methods.authenticate = async function (
this: AuthBaseDocument,
password: string
) {
AuthSchema.methods.authenticate = async function (this: AuthBaseDocument, password: string) {
const strategy = await this.getStrategy();
return !!strategy && verify(password, strategy.key);
};
AuthSchema.methods.getStrategy = async function (
this: AuthBaseDocument,
method = STRATEGIES.LOCAL
) {
const doc = await this.populate<{ strategies: StrategyDocument[] }>(
"strategies"
);
return (
doc.strategies.filter((strategy) => strategy.method === method).pop() ||
null
);
AuthSchema.methods.getStrategy = async function (this: AuthBaseDocument, method = STRATEGIES.LOCAL) {
const doc = await this.populate<{ strategies: StrategyDocument[] }>('strategies');
return doc.strategies.filter((strategy) => strategy.method === method).pop() || null;
};
AuthSchema.statics = {

View File

@@ -1,14 +1,8 @@
import {
InferSchemaType,
Model,
Schema,
StringSchemaDefinition,
Types,
} from "mongoose";
import { InferSchemaType, Model, Schema, StringSchemaDefinition, Types } from 'mongoose';
import { Payload } from "@mifi/services-common/lib/types/Payload";
import { Payload } from '@mifi/services-common/lib/types/Payload';
import { Action } from "../constants/action";
import { Action } from '../constants/action';
export interface Log {
action: Action;
@@ -31,7 +25,7 @@ export const LogSchema = new Schema<Log, LogModel>(
{
minimize: true,
timestamps: true,
}
},
);
LogSchema.statics = {

View File

@@ -1,17 +1,10 @@
import {
Document,
InferSchemaType,
Model,
Schema,
StringSchemaDefinition,
Types,
} from "mongoose";
import { Document, InferSchemaType, Model, Schema, StringSchemaDefinition, Types } from 'mongoose';
import { STRATEGIES } from "../constants/strategies";
import { encrypt } from "../utils/password";
import { COLL_AUTH } from "../constants/db";
import { AuthDocument } from "./auth";
import { Strategy } from "..";
import { STRATEGIES } from '../constants/strategies';
import { encrypt } from '../utils/password';
import { COLL_AUTH } from '../constants/db';
import { AuthDocument } from './auth';
import { Strategy } from '..';
export interface Strategy {
method: STRATEGIES;
@@ -57,31 +50,27 @@ export const StrategySchema = new Schema<StrategyDocument, StrategyModel>(
{
minimize: true,
timestamps: true,
}
},
);
StrategySchema.methods.getPopulatedStrategy = async function (
this: StrategyDocument
) {
return this.populate<StrategyPopulatedDocument>("parent");
StrategySchema.methods.getPopulatedStrategy = async function (this: StrategyDocument) {
return this.populate<StrategyPopulatedDocument>('parent');
};
StrategySchema.methods.getAuthRecord = async function (this: StrategyDocument) {
return (await this.getPopulatedStrategy()).parent;
};
StrategySchema.pre("save", async function save(next) {
if (typeof this.method === "undefined") {
StrategySchema.pre('save', async function save(next) {
if (typeof this.method === 'undefined') {
return next(new Error(`Strategy requires a method.`));
}
if (await Strategy.findOne({ method: this.method, parent: this.parent })) {
return next(
new Error(`${this.method} strategy already exists for this user.`)
);
return next(new Error(`${this.method} strategy already exists for this user.`));
}
if (this.method !== STRATEGIES.LOCAL || !this.isModified("key")) {
if (this.method !== STRATEGIES.LOCAL || !this.isModified('key')) {
return next();
}

View File

@@ -1,14 +1,8 @@
import {
InferSchemaType,
Model,
Schema,
StringSchemaDefinition,
Types,
} from "mongoose";
import { InferSchemaType, Model, Schema, StringSchemaDefinition, Types } from 'mongoose';
import { TokenType } from "../constants/tokens";
import { getDefaultExpiresFor } from "../utils/getDefaultExpiresFor";
import { sign, verify } from "../utils/jwt";
import { TokenType } from '../constants/tokens';
import { getDefaultExpiresFor } from '../utils/getDefaultExpiresFor';
import { sign, verify } from '../utils/jwt';
export interface Token {
auth: StringSchemaDefinition;
@@ -31,7 +25,7 @@ export const TokenSchema = new Schema<Token, TokenModel>(
{
minimize: true,
timestamps: true,
}
},
);
TokenSchema.statics = {
@@ -42,11 +36,7 @@ TokenSchema.statics = {
return { success: acknowledged, deletedCount };
},
async getToken(
type: TokenType,
auth: StringSchemaDefinition,
expires?: number
) {
async getToken(type: TokenType, auth: StringSchemaDefinition, expires?: number) {
const existing = await this.findOne({ type, auth });
if (existing) {
await existing.deleteOne();

View File

@@ -1,10 +1,6 @@
import {
LOGIN_VALID_TIMEOUT,
RESET_VALID_TIMEOUT,
VERIFY_VALID_TIMEOUT,
} from "../constants/env";
import { TokenType } from "../constants/tokens";
import { parseTimeoutToMs } from "../utils/parseTimeoutToMs";
import { LOGIN_VALID_TIMEOUT, RESET_VALID_TIMEOUT, VERIFY_VALID_TIMEOUT } from '../constants/env';
import { TokenType } from '../constants/tokens';
import { parseTimeoutToMs } from '../utils/parseTimeoutToMs';
export const getDefaultExpiresFor = (type: TokenType | void) => {
if (type === TokenType.RESET) {

View File

@@ -1,7 +1,7 @@
import { sign } from "../utils/jwt";
import { LOGIN_VALID_TIMEOUT } from "../constants/env";
import { parseTimeoutToMs } from "../utils/parseTimeoutToMs";
import { AuthDocument } from "../schema/auth";
import { sign } from '../utils/jwt';
import { LOGIN_VALID_TIMEOUT } from '../constants/env';
import { parseTimeoutToMs } from '../utils/parseTimeoutToMs';
import { AuthDocument } from '../schema/auth';
export const getLoginToken = ({ record: sub, status }: AuthDocument) =>
sign({

View File

@@ -1,5 +1,5 @@
import jwt from "jsonwebtoken";
import { JWT_AUDIENCE, JWT_ISSUER, JWT_SECRET } from "../constants/env";
import jwt from 'jsonwebtoken';
import { JWT_AUDIENCE, JWT_ISSUER, JWT_SECRET } from '../constants/env';
export interface TokenProps {
aud?: string;
exp?: number | Date;
@@ -13,15 +13,11 @@ export type SignProps = string | TokenProps | void;
export const sign = (props: SignProps) => {
const today = new Date();
const { sub = null, ...rest }: TokenProps =
typeof props === "string" || typeof props === "undefined"
? { sub: props || null }
: props;
typeof props === 'string' || typeof props === 'undefined' ? { sub: props || null } : props;
let { exp } = rest;
if (!exp) {
exp = new Date(today);
exp.setDate(
today.getDate() + parseInt(process.env.JWT_DAYS_VALID as string)
);
exp.setDate(today.getDate() + parseInt(process.env.JWT_DAYS_VALID as string));
exp = exp.getTime() / 1000;
}
return jwt.sign(
@@ -32,7 +28,7 @@ export const sign = (props: SignProps) => {
iat: today.getTime(),
iss: rest.iss || JWT_ISSUER,
},
JWT_SECRET
JWT_SECRET,
);
};

View File

@@ -1,11 +1,5 @@
import {
RESET_ROUTE,
ROUTE_PREFIX,
VERIFICATION_ROUTE,
} from "../constants/env";
import { RESET_ROUTE, ROUTE_PREFIX, VERIFICATION_ROUTE } from '../constants/env';
export const getPasswordResetPath = (token: string) =>
`${ROUTE_PREFIX}${RESET_ROUTE}?t=${token}`;
export const getPasswordResetPath = (token: string) => `${ROUTE_PREFIX}${RESET_ROUTE}?t=${token}`;
export const getVerificationPath = (token: string) =>
`${ROUTE_PREFIX}${VERIFICATION_ROUTE}?t=${token}`;
export const getVerificationPath = (token: string) => `${ROUTE_PREFIX}${VERIFICATION_ROUTE}?t=${token}`;

View File

@@ -2,11 +2,11 @@ export const parseTimeoutToMs = (timeout: string) => {
const match = timeout.match(/(?<number>\d+)(?<unit>d|h|m)/gi)?.groups || {};
const { number, unit } = match;
switch (unit) {
case "d":
case 'd':
return 1000 * 60 * 60 * 24 * parseInt(number);
case "h":
case 'h':
return 1000 * 60 * 60 * parseInt(number);
case "m":
case 'm':
default:
return 1000 * 60 * parseInt(number) || 1;
}

View File

@@ -1,12 +1,12 @@
import { pbkdf2Sync, randomBytes } from "crypto";
import { pbkdf2Sync, randomBytes } from 'crypto';
export const encrypt = (password: string) => {
const salt = randomBytes(16).toString("hex");
const hash = pbkdf2Sync(password, salt, 10000, 512, "sha512").toString("hex");
const salt = randomBytes(16).toString('hex');
const hash = pbkdf2Sync(password, salt, 10000, 512, 'sha512').toString('hex');
return `${salt}:${hash}`;
};
export const verify = (test: string, secret: string) => {
const [salt, hash] = secret.split(":");
return pbkdf2Sync(test, salt, 10000, 512, "sha512").toString("hex") === hash;
const [salt, hash] = secret.split(':');
return pbkdf2Sync(test, salt, 10000, 512, 'sha512').toString('hex') === hash;
};

View File

@@ -1,7 +1,7 @@
import { sign } from "./jwt";
import { LOGIN_VALID_TIMEOUT } from "../constants/env";
import { Status } from "../constants/auth";
import { parseTimeoutToMs } from "./parseTimeoutToMs";
import { sign } from './jwt';
import { LOGIN_VALID_TIMEOUT } from '../constants/env';
import { Status } from '../constants/auth';
import { parseTimeoutToMs } from './parseTimeoutToMs';
export const generateLoginToken = (sub: string, status: Status) =>
sign({