mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
refactor: adopt new ESLint rule set for FP (#111)
This commit is contained in:
parent
af942d2027
commit
7ae7912642
16 changed files with 519 additions and 145 deletions
|
@ -37,13 +37,14 @@
|
|||
"module-alias": "^2.2.2",
|
||||
"nanoid": "^3.1.23",
|
||||
"oidc-provider": "^7.4.1",
|
||||
"p-retry": "^4.6.1",
|
||||
"slonik": "^23.8.3",
|
||||
"slonik-interceptor-preset": "^1.2.10",
|
||||
"zod": "^3.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@logto/eslint-config": "^0.1.3",
|
||||
"@logto/ts-config": "^0.1.3",
|
||||
"@logto/eslint-config": "^0.2.0",
|
||||
"@logto/ts-config": "^0.2.0",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/koa": "^2.13.3",
|
||||
"@types/koa-logger": "^3.1.1",
|
||||
|
|
|
@ -40,7 +40,8 @@ const detectLanguageFromHeaders = (headers: IncomingHttpHeaders): string[] =>
|
|||
?.split(',')
|
||||
.map((string) => resolveLanguage(string))
|
||||
.filter((value): value is NonNullable<typeof value> => Boolean(value))
|
||||
.sort((a, b) => b[1] - a[1]) // LOG-81: `.sort()` is a mutation, consider ban it later
|
||||
.slice()
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.map(([locale]) => locale) ?? [];
|
||||
|
||||
const detectLanguage = <StateT, ContextT extends IRouterParamContext, ResponseBodyT>(
|
||||
|
|
|
@ -90,6 +90,8 @@ export default function koaGuard<
|
|||
return guard(ctx, next);
|
||||
};
|
||||
|
||||
// Intended
|
||||
// eslint-disable-next-line @silverhand/fp/no-mutation
|
||||
guardMiddleware.config = { query, body, params };
|
||||
|
||||
return guardMiddleware;
|
||||
|
|
|
@ -24,20 +24,20 @@ export default function koaUIProxy<
|
|||
});
|
||||
const staticProxy: Middleware = serveStatic(PATH_TO_UI_DIST);
|
||||
|
||||
return async (context, next) => {
|
||||
return async (ctx, next) => {
|
||||
// Route has been handled by one of mounted apps
|
||||
if (mountedApps.some((app) => context.request.path.startsWith(`/${app}`))) {
|
||||
if (mountedApps.some((app) => ctx.request.path.startsWith(`/${app}`))) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!isProduction) {
|
||||
return developmentProxy(context, next);
|
||||
return developmentProxy(ctx, next);
|
||||
}
|
||||
|
||||
if (!uiDistFiles.some((file) => context.request.path.startsWith(`/${file}`))) {
|
||||
context.request.path = '/';
|
||||
if (!uiDistFiles.some((file) => ctx.request.path.startsWith(`/${file}`))) {
|
||||
ctx.request.path = '/';
|
||||
}
|
||||
|
||||
return staticProxy(context, next);
|
||||
return staticProxy(ctx, next);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { PasswordEncryptionMethod } from '@logto/schemas';
|
||||
import { nanoid } from 'nanoid';
|
||||
import pRetry from 'p-retry';
|
||||
import { object, string } from 'zod';
|
||||
|
||||
import RequestError from '@/errors/RequestError';
|
||||
|
@ -12,17 +13,20 @@ import { AnonymousRouter } from './types';
|
|||
|
||||
const userId = buildIdGenerator(12);
|
||||
|
||||
const generateUserId = async (maxRetries = 500) => {
|
||||
for (let i = 0; i < maxRetries; ++i) {
|
||||
const id = userId();
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
if (!(await hasUserWithId(id))) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
// LOG-89: Add unit tests
|
||||
const generateUserId = async (retries = 500) =>
|
||||
pRetry(
|
||||
async () => {
|
||||
const id = userId();
|
||||
|
||||
throw new Error('Cannot generate user ID in reasonable retries');
|
||||
};
|
||||
if (!(await hasUserWithId(id))) {
|
||||
return id;
|
||||
}
|
||||
|
||||
throw new Error('Cannot generate user ID in reasonable retries');
|
||||
},
|
||||
{ retries }
|
||||
);
|
||||
|
||||
export default function userRoutes<T extends AnonymousRouter>(router: T) {
|
||||
router.post(
|
||||
|
|
|
@ -6,6 +6,7 @@ import { number, string } from 'zod';
|
|||
import assert from '@/utils/assert';
|
||||
|
||||
import { assertEnv } from './env';
|
||||
import repeat from './repeat';
|
||||
|
||||
const peppers = string()
|
||||
.array()
|
||||
|
@ -31,13 +32,11 @@ export const encryptPassword = (
|
|||
|
||||
assert(pepper, 'password.pepper_not_found');
|
||||
|
||||
let result = password;
|
||||
|
||||
for (let i = 0; i < iterationCount; ++i) {
|
||||
result = createHash('sha256')
|
||||
.update(salt + result + pepper)
|
||||
.digest('hex');
|
||||
}
|
||||
const result = repeat(iterationCount, password, (password) =>
|
||||
createHash('sha256')
|
||||
.update(salt + password + pepper)
|
||||
.digest('hex')
|
||||
);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
|
15
packages/core/src/utils/repeat.ts
Normal file
15
packages/core/src/utils/repeat.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
// LOG-79: Add this into `essentials` package
|
||||
// Disable FP rules here to use the performant approach while keep the function itself "FP"
|
||||
/* eslint-disable @silverhand/fp/no-let, @silverhand/fp/no-mutation */
|
||||
const repeat = <T>(times: number, initial: T, iterate: (accumulator: T) => T) => {
|
||||
let result = initial;
|
||||
|
||||
while (times--) {
|
||||
result = iterate(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
/* eslint-enable @silverhand/fp/no-let, @silverhand/fp/no-mutation */
|
||||
|
||||
export default repeat;
|
|
@ -25,8 +25,8 @@
|
|||
"url": "https://github.com/logto-io/logto/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@logto/eslint-config": "^0.1.3",
|
||||
"@logto/ts-config": "^0.1.3",
|
||||
"@logto/eslint-config": "^0.2.0",
|
||||
"@logto/ts-config": "^0.2.0",
|
||||
"eslint": "^7.32.0",
|
||||
"lint-staged": "^11.1.1",
|
||||
"prettier": "^2.3.2",
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
"node": ">=14.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@logto/eslint-config": "^0.1.3",
|
||||
"@logto/eslint-config": "^0.2.0",
|
||||
"@logto/essentials": "^1.1.0-rc.2",
|
||||
"@logto/ts-config": "^0.1.3",
|
||||
"@logto/ts-config": "^0.2.0",
|
||||
"@types/lodash.uniq": "^4.5.6",
|
||||
"@types/node": "14",
|
||||
"@types/pluralize": "^0.0.29",
|
||||
|
|
|
@ -133,6 +133,8 @@ const generate = async () => {
|
|||
// Generate DB entry types
|
||||
await Promise.all(
|
||||
generated.map(async ([file, { tables }]) => {
|
||||
// LOG-88 Need refactor, disable mutation rules for now.
|
||||
/* eslint-disable @silverhand/fp/no-mutating-methods */
|
||||
const tsTypes: string[] = [];
|
||||
const customTypes: string[] = [];
|
||||
const tableWithTypes = tables.map<TableWithType>(({ fields, ...rest }) => ({
|
||||
|
@ -155,6 +157,7 @@ const generate = async () => {
|
|||
if (tableWithTypes.length > 0) {
|
||||
tsTypes.push('GeneratedSchema', 'Guard');
|
||||
}
|
||||
/* eslint-enable @silverhand/fp/no-mutating-methods */
|
||||
|
||||
const importZod = conditionalString(
|
||||
tableWithTypes.length > 0 && "import { z } from 'zod';\n\n"
|
||||
|
|
|
@ -31,10 +31,10 @@
|
|||
"devDependencies": {
|
||||
"@babel/core": "^7.14.6",
|
||||
"@jest/types": "^27.0.6",
|
||||
"@logto/eslint-config": "^0.1.3",
|
||||
"@logto/eslint-config-react": "^0.1.3",
|
||||
"@logto/ts-config": "^0.1.3",
|
||||
"@logto/ts-config-react": "^0.1.3",
|
||||
"@logto/eslint-config": "^0.2.0",
|
||||
"@logto/eslint-config-react": "^0.2.0",
|
||||
"@logto/ts-config": "^0.2.0",
|
||||
"@logto/ts-config-react": "^0.2.0",
|
||||
"@testing-library/react": "^12.0.0",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/react": "^17.0.14",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
|
||||
|
||||
// eslint-disable-next-line @silverhand/fp/no-mutating-methods
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: jest.fn().mockImplementation((query) => ({
|
||||
|
|
|
@ -8,7 +8,7 @@ const Consent = () => {
|
|||
|
||||
useEffect(() => {
|
||||
const autoConsent = async () => {
|
||||
window.location.href = (await consent()).redirectTo;
|
||||
window.location.assign((await consent()).redirectTo);
|
||||
};
|
||||
|
||||
void autoConsent();
|
||||
|
|
|
@ -29,7 +29,7 @@ const Register: FC = () => {
|
|||
|
||||
useEffect(() => {
|
||||
if (result?.redirectTo) {
|
||||
window.location.href = result.redirectTo;
|
||||
window.location.assign(result.redirectTo);
|
||||
}
|
||||
}, [result]);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ const SignIn: FC = () => {
|
|||
|
||||
useEffect(() => {
|
||||
if (result?.redirectTo) {
|
||||
window.location.href = result.redirectTo;
|
||||
window.location.assign(result.redirectTo);
|
||||
}
|
||||
}, [result]);
|
||||
|
||||
|
|
563
pnpm-lock.yaml
563
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue