Skip to content

Commit

Permalink
Merge pull request #131 from UN-OCHA/HPC-9238
Browse files Browse the repository at this point in the history
HPC-9238: Upgrade to Node.js v20
  • Loading branch information
Pl217 authored Nov 2, 2023
2 parents b62c0a4 + 37b8b4d commit 9aeb13a
Show file tree
Hide file tree
Showing 53 changed files with 1,051 additions and 756 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.eslintrc.js
18 changes: 18 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const baseConfig = require('@unocha/hpc-repo-tools/eslintrc.base');

module.exports = {
...baseConfig,
parserOptions: {
project: true,
tsconfigRootDir: __dirname,
},
overrides: [
...baseConfig.overrides,
{
files: ['*.{ts,tsx}'],
rules: {
'@typescript-eslint/no-explicit-any': 'warn',
},
},
],
};
6 changes: 0 additions & 6 deletions .eslintrc.json

This file was deleted.

4 changes: 4 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
a75798a4a9222ac2cc02eb6a007d038b8c3deab7
37b192f172a0565f0404559813c5ef276896d5c5
4264d288faff9b94878c60d274362a0764484610
761b9128719fbd04312337d07dcb9ff720b197d8
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ jobs:
timeout-minutes: 25
steps:
- name: Checkout repository
uses: actions/checkout@v3
- uses: actions/setup-node@v3
uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
node-version: '20'
- name: Install packages
run: yarn install --frozen-lockfile
- name: TypeScript compiler checks
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- run: npm install
- run: npm publish
Expand Down
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{
"name": "@unocha/hpc-api-core",
"version": "6.2.0",
"version": "7.0.0",
"description": "Core libraries supporting HPC.Tools API Backend",
"license": "Apache-2.0",
"private": false,
"scripts": {
"check-types": "tsc --noEmit",
"prepare": "husky install",
"prepare": "[ -d .git ] && git config blame.ignoreRevsFile .git-blame-ignore-revs; husky install",
"lint-prettier": "prettier -c .",
"lint-eslint": "eslint --quiet .",
"lint": "yarn lint-prettier && yarn lint-eslint"
},
"engines": {
"node": ">=18.16.1",
"node": ">=18.18.2 || >=20.9.0",
"yarn": ">=1.22.10"
},
"dependencies": {
Expand All @@ -23,16 +23,16 @@
"knex": "0.21.1",
"lodash": "^4.17.21",
"node-fetch": "2.6.9",
"pg": "^8.10.0"
"pg": "^8.11.3"
},
"devDependencies": {
"@types/node": "^18.16.19",
"@unocha/hpc-repo-tools": "^3.0.1",
"eslint": "^8.44.0",
"@types/node": "^20.8.10",
"@unocha/hpc-repo-tools": "^4.0.0",
"eslint": "^8.52.0",
"husky": "^8.0.3",
"lint-staged": "^13.2.2",
"prettier": "2.8.8",
"typescript": "^5.1.6"
"lint-staged": "^15.0.2",
"prettier": "3.0.3",
"typescript": "^5.2.2"
},
"lint-staged": {
"*.{ts,js}": [
Expand Down
4 changes: 2 additions & 2 deletions src/auth/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* TODO: extend this with some cross-container cache such as redis or memcached
*/

import { createHash } from 'crypto';
import { createHash } from 'node:crypto';

const sha256 = (str: string) => createHash('sha256').update(str).digest('hex');

Expand All @@ -28,7 +28,7 @@ export class HashTableCache<V> {
public store = (key: string, value: V, cacheTime?: Date): void => {
this.map.set(sha256(key), {
value,
time: cacheTime || new Date(),
time: cacheTime ?? new Date(),
});
this.clearExpiredValues();
};
Expand Down
12 changes: 6 additions & 6 deletions src/auth/hid.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import * as fetch from 'node-fetch';
import { URL } from 'url';
import * as t from 'io-ts';
import * as fetch from 'node-fetch';
import { URL } from 'node:url';

import { HashTableCache } from './cache';
import { Context } from '../lib/context';
import { type Context } from '../lib/context';
import { ForbiddenError } from '../util/error';
import { HashTableCache } from './cache';

const HID_ACCOUNT_INFO = t.type({
sub: t.string,
Expand Down Expand Up @@ -38,7 +38,7 @@ export const HID_CACHE = new HashTableCache<HIDResponse>({
export const getHidInfo = async (
context: Context
): Promise<HIDInfo | undefined> => {
const { token } = context;
const { config, token } = context;

if (!token) {
return undefined;
Expand All @@ -53,7 +53,7 @@ export const getHidInfo = async (

throw new ForbiddenError(existing.message);
} else {
const accountUrl = new URL('/account.json', context.config.authBaseUrl);
const accountUrl = new URL('/account.json', config.authBaseUrl);
// Reference fetch.default to allow for mocking
const res = await fetch.default(accountUrl, {
headers: {
Expand Down
55 changes: 27 additions & 28 deletions src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,32 @@
* This file is a new (type-safe) interface for common authentication functions
* ahead of the auth refactor outlined in HPC-6999
*/
import v4Models from '../db';
import { AuthTargetId } from '../db/models/authTarget';
import { ParticipantId } from '../db/models/participant';
import { InstanceOfModel } from '../db/util/types';
import { createBrandedValue } from '../util/types';
import * as crypto from 'crypto';
import { promisify } from 'util';
import * as crypto from 'node:crypto';
import { promisify } from 'node:util';
import type v4Models from '../db';
import { type AuthTargetId } from '../db/models/authTarget';
import { type ParticipantId } from '../db/models/participant';
import type { Database } from '../db/type';
import { Op } from '../db/util/conditions';
import { createDeferredFetcher } from '../db/util/deferred';
import { type InstanceOfModel } from '../db/util/types';
import { type Context } from '../lib/context';
import { type SharedLogContext } from '../lib/logging';
import { organizeObjectsByUniqueProperty } from '../util';
import { Context } from '../lib/context';
import { SharedLogContext } from '../lib/logging';
import { createBrandedValue } from '../util/types';
import * as hid from './hid';
import {
AUTH_PERMISSIONS,
GrantedPermissions,
hasRequiredPermissions,
PermissionStrings,
RequiredPermissionsCondition,
type GrantedPermissions,
type PermissionStrings,
type RequiredPermissionsCondition,
} from './permissions';
import {
calculatePermissionsFromRolesGrant,
filterValidRoleStrings,
RolesGrant,
type RolesGrant,
} from './roles';
import { Op } from '../db/util/conditions';

const randomBytes = promisify(crypto.randomBytes);

Expand Down Expand Up @@ -182,7 +182,7 @@ export const getLoggedInParticipant = async (
* currently logged in user.
*/
export const actionIsPermitted = async <
AdditionalGlobalPermissions extends string
AdditionalGlobalPermissions extends string,
>(
condition: RequiredPermissionsCondition<AdditionalGlobalPermissions>,
context: Context
Expand Down Expand Up @@ -325,13 +325,13 @@ export const getRoleGrantsForUser = async ({
users: [user],
context,
})
).get(user) || [];
).get(user) ?? [];

/**
* Calculate the complete set of permissions for the logged in participant
*/
export const calculatePermissions = async <
AdditionalGlobalPermissions extends string
AdditionalGlobalPermissions extends string,
>(
context: Context
): Promise<GrantedPermissions<AdditionalGlobalPermissions>> => {
Expand All @@ -353,12 +353,12 @@ export const calculatePermissions = async <
};

export const getAllowedPermissionsFromGrants = async <
AdditionalGlobalPermissions extends string
AdditionalGlobalPermissions extends string,
>(
participantId: ParticipantId,
context: Context,
calculatePermissionsFn: typeof calculatePermissionsFromRolesGrant
): Promise<GrantedPermissions<AdditionalGlobalPermissions>[]> => {
): Promise<Array<GrantedPermissions<AdditionalGlobalPermissions>>> => {
const { models } = context;

const grants = await getRoleGrantsForUser({
Expand All @@ -373,21 +373,21 @@ export const getAllowedPermissionsFromGrants = async <
// Calculate the allowed permissions for each of these grants
return (await Promise.all(
grants.map((grant) => calculatePermissionsFn(grant, fetchers))
)) as GrantedPermissions<AdditionalGlobalPermissions>[];
)) as Array<GrantedPermissions<AdditionalGlobalPermissions>>;
};

export const mergePermissionsFromGrants = <
AdditionalGlobalPermissions extends string
AdditionalGlobalPermissions extends string,
>(
allowedFromGrants: GrantedPermissions<AdditionalGlobalPermissions>[]
allowedFromGrants: Array<GrantedPermissions<AdditionalGlobalPermissions>>
): GrantedPermissions<AdditionalGlobalPermissions> => {
const allowed: GrantedPermissions<AdditionalGlobalPermissions> = {};

const mergeAllowedPermissions = <
Type extends keyof Omit<
GrantedPermissions<AdditionalGlobalPermissions>,
'global'
>
>,
>(
type: Type,
additions: Map<number, Set<PermissionStrings<Type>>>
Expand Down Expand Up @@ -415,15 +415,14 @@ export const mergePermissionsFromGrants = <
continue;
}
if (granted.global) {
allowed.global = allowed.global || new Set();
allowed.global = allowed.global ?? new Set();
for (const p of granted.global) {
allowed.global.add(p);
}
}
for (const [key, obj] of Object.entries(granted) as [
keyof typeof granted,
any
][]) {
for (const [key, obj] of Object.entries(granted) as Array<
[keyof typeof granted, any]
>) {
if (key !== 'global') {
mergeAllowedPermissions(key, obj);
}
Expand Down
14 changes: 7 additions & 7 deletions src/auth/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,13 +283,13 @@ export type RequiredPermission<AdditionalGlobalPermissions extends string> =
* A list of permissions that must all be granted for an access to be permitted
*/
type RequiredPermissionsConjunctionAnd<
AdditionalGlobalPermissions extends string
AdditionalGlobalPermissions extends string,
> = {
and: RequiredPermissionsCondition<AdditionalGlobalPermissions>[];
and: Array<RequiredPermissionsCondition<AdditionalGlobalPermissions>>;
};

export type RequiredPermissionsConjunction<
AdditionalGlobalPermissions extends string
AdditionalGlobalPermissions extends string,
> =
| RequiredPermissionsConjunctionAnd<AdditionalGlobalPermissions>
| RequiredPermission<AdditionalGlobalPermissions>;
Expand All @@ -305,13 +305,13 @@ export const isAnd = <AdditionalGlobalPermissions extends string>(
* Disjunctive Normal Form (https://en.wikipedia.org/wiki/Disjunctive_normal_form)
*/
export type RequiredPermissionsConditionOr<
AdditionalGlobalPermissions extends string
AdditionalGlobalPermissions extends string,
> = {
or: RequiredPermissionsCondition<AdditionalGlobalPermissions>[];
or: Array<RequiredPermissionsCondition<AdditionalGlobalPermissions>>;
};

export type RequiredPermissionsCondition<
AdditionalGlobalPermissions extends string
AdditionalGlobalPermissions extends string,
> =
| RequiredPermissionsConditionOr<AdditionalGlobalPermissions>
| RequiredPermissionsConjunction<AdditionalGlobalPermissions>
Expand All @@ -324,7 +324,7 @@ export const isOr = <AdditionalGlobalPermissions extends string>(
!!(conj as RequiredPermissionsConditionOr<AdditionalGlobalPermissions>).or;

export const hasRequiredPermissions = <
AdditionalGlobalPermissions extends string
AdditionalGlobalPermissions extends string,
>(
granted: GrantedPermissions<AdditionalGlobalPermissions>,
condition: RequiredPermissionsCondition<AdditionalGlobalPermissions>
Expand Down
Loading

0 comments on commit 9aeb13a

Please sign in to comment.