pangea-server 3.3.1 → 3.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/access-token.class.d.ts +13 -0
- package/dist/auth/access-token.class.js +28 -0
- package/dist/auth/auth.helpers.d.ts +17 -0
- package/dist/auth/auth.helpers.js +73 -0
- package/dist/auth/auth.types.d.ts +11 -0
- package/dist/auth/auth.types.js +2 -0
- package/dist/auth/base-auth.class.d.ts +11 -0
- package/dist/auth/base-auth.class.js +35 -0
- package/dist/auth/index.d.ts +4 -0
- package/dist/auth/index.js +20 -0
- package/dist/helpers/job.helpers.d.ts +15 -2
- package/dist/helpers/job.helpers.js +35 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/router/app-router.class.d.ts +2 -2
- package/dist/router/call-controller.d.ts +2 -2
- package/dist/router/call-controller.js +3 -3
- package/dist/router/router.types.d.ts +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { User } from '../database';
|
|
2
|
+
import type { UserCtor } from './auth.types';
|
|
3
|
+
export declare class AccessToken {
|
|
4
|
+
private __privateKey;
|
|
5
|
+
constructor(privateKey: string);
|
|
6
|
+
getKey(userCtor: UserCtor): string;
|
|
7
|
+
createToken(userCtor: UserCtor, id: ModelId): string;
|
|
8
|
+
verifyToken(token: string): Record<string, number>;
|
|
9
|
+
getTokenData(userCtor: UserCtor, user: User): {
|
|
10
|
+
accessToken: string;
|
|
11
|
+
user: User;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AccessToken = void 0;
|
|
7
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
+
// helpers
|
|
9
|
+
const pangea_helpers_1 = require("pangea-helpers");
|
|
10
|
+
class AccessToken {
|
|
11
|
+
constructor(privateKey) {
|
|
12
|
+
this.__privateKey = privateKey;
|
|
13
|
+
}
|
|
14
|
+
getKey(userCtor) {
|
|
15
|
+
return `${(0, pangea_helpers_1.getFirstChartInLowercase)(userCtor.name)}Id`;
|
|
16
|
+
}
|
|
17
|
+
createToken(userCtor, id) {
|
|
18
|
+
const key = this.getKey(userCtor);
|
|
19
|
+
return jsonwebtoken_1.default.sign({ [key]: id }, this.__privateKey, { expiresIn: 60 * 60 * 24 * 365 });
|
|
20
|
+
}
|
|
21
|
+
verifyToken(token) {
|
|
22
|
+
return jsonwebtoken_1.default.verify(token, this.__privateKey);
|
|
23
|
+
}
|
|
24
|
+
getTokenData(userCtor, user) {
|
|
25
|
+
return { accessToken: this.createToken(userCtor, user.id), user };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.AccessToken = AccessToken;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AccessToken } from './access-token.class';
|
|
2
|
+
import { User } from '../database';
|
|
3
|
+
import type { UserCtor, AuthMap } from './auth.types';
|
|
4
|
+
type AuthHeader = string | undefined;
|
|
5
|
+
export declare function login<U extends User>(authHeader: AuthHeader, db: Db, accessToken: AccessToken, userCtor: BaseModelCtor<U>, extraWhere?: Where<U>): Promise<{
|
|
6
|
+
accessToken: string;
|
|
7
|
+
user: User;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function validateAccessToken(authHeader: AuthHeader, db: Db, accessToken: AccessToken, userCtor: UserCtor): Promise<{
|
|
10
|
+
accessToken: string;
|
|
11
|
+
user: User;
|
|
12
|
+
}>;
|
|
13
|
+
export declare function getUserFromToken(authHeader: AuthHeader, db: Db, accessToken: AccessToken, userCtor: UserCtor): Promise<User | null> | null;
|
|
14
|
+
export declare function getUsersFromToken(authHeader: AuthHeader, db: Db, accessToken: AccessToken, authMap: AuthMap): Promise<{
|
|
15
|
+
[k: string]: User | null;
|
|
16
|
+
}>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getUsersFromToken = exports.getUserFromToken = exports.validateAccessToken = exports.login = void 0;
|
|
4
|
+
// helpers
|
|
5
|
+
const helpers_1 = require("../helpers");
|
|
6
|
+
async function login(authHeader, db, accessToken, userCtor, extraWhere = {}) {
|
|
7
|
+
if (!authHeader?.startsWith('Basic '))
|
|
8
|
+
helpers_1.AppError.ThrowInvalidCredentials();
|
|
9
|
+
const base64 = authHeader.slice(6);
|
|
10
|
+
const decoded = Buffer.from(base64, 'base64').toString('utf-8');
|
|
11
|
+
const [username, password] = decoded.split(':');
|
|
12
|
+
if (!username || !password)
|
|
13
|
+
helpers_1.AppError.ThrowInvalidCredentials();
|
|
14
|
+
const where = { ...extraWhere, username };
|
|
15
|
+
const user = await db.findOneOrNull(userCtor, where, { scopes: ['withHiddenAttributes'] });
|
|
16
|
+
if (!user)
|
|
17
|
+
helpers_1.AppError.ThrowInvalidCredentials();
|
|
18
|
+
const isPasswordValid = await (0, helpers_1.comparePasswords)(password, user.password);
|
|
19
|
+
if (!isPasswordValid)
|
|
20
|
+
helpers_1.AppError.ThrowInvalidCredentials();
|
|
21
|
+
return accessToken.getTokenData(userCtor, user);
|
|
22
|
+
}
|
|
23
|
+
exports.login = login;
|
|
24
|
+
async function validateAccessToken(authHeader, db, accessToken, userCtor) {
|
|
25
|
+
const user = await getUserFromToken(authHeader, db, accessToken, userCtor);
|
|
26
|
+
if (!user)
|
|
27
|
+
helpers_1.AppError.ThrowUnauthorized();
|
|
28
|
+
return accessToken.getTokenData(userCtor, user);
|
|
29
|
+
}
|
|
30
|
+
exports.validateAccessToken = validateAccessToken;
|
|
31
|
+
function getUserFromToken(authHeader, db, accessToken, userCtor) {
|
|
32
|
+
try {
|
|
33
|
+
const token = getBearerToken(authHeader);
|
|
34
|
+
const payload = accessToken.verifyToken(token);
|
|
35
|
+
const key = accessToken.getKey(userCtor);
|
|
36
|
+
const id = payload[key];
|
|
37
|
+
if (!id)
|
|
38
|
+
return null;
|
|
39
|
+
return db.findOneOrNull(userCtor, id);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.getUserFromToken = getUserFromToken;
|
|
46
|
+
async function getUsersFromToken(authHeader, db, accessToken, authMap) {
|
|
47
|
+
try {
|
|
48
|
+
const token = getBearerToken(authHeader);
|
|
49
|
+
const payload = accessToken.verifyToken(token);
|
|
50
|
+
const results = await Promise.all(Object.entries(authMap).map(async ([type, userCtor]) => {
|
|
51
|
+
const key = accessToken.getKey(userCtor);
|
|
52
|
+
const id = payload[key];
|
|
53
|
+
if (!id)
|
|
54
|
+
return [type, null];
|
|
55
|
+
const user = await db.findOneOrNull(userCtor, id);
|
|
56
|
+
return [type, user];
|
|
57
|
+
}));
|
|
58
|
+
return Object.fromEntries(results);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return Object.fromEntries(Object.keys(authMap).map((type) => [type, null]));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.getUsersFromToken = getUsersFromToken;
|
|
65
|
+
// internal functions
|
|
66
|
+
function getBearerToken(authHeader) {
|
|
67
|
+
if (!authHeader)
|
|
68
|
+
throw new Error('Missing authorization header');
|
|
69
|
+
const [type, token] = authHeader.split(' ');
|
|
70
|
+
if (type !== 'Bearer' || !token)
|
|
71
|
+
throw new Error('Invalid authorization format');
|
|
72
|
+
return token;
|
|
73
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseAuth } from './base-auth.class';
|
|
2
|
+
import { User } from '../database';
|
|
3
|
+
export type UserCtor = BaseModelCtor<User>;
|
|
4
|
+
export type AuthMap = Record<string, UserCtor>;
|
|
5
|
+
export type UserType<AM extends AuthMap> = keyof AM;
|
|
6
|
+
export type AuthUsers<AM extends AuthMap> = {
|
|
7
|
+
[K in keyof AM]: InstanceType<AM[K]> | null;
|
|
8
|
+
};
|
|
9
|
+
export interface AuthCtor<AM extends AuthMap, AU extends AuthUsers<AM>, BA extends BaseAuth<AM>> {
|
|
10
|
+
new (authUsers: AU): BA;
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AuthMap, UserType, AuthUsers } from './auth.types';
|
|
2
|
+
export declare abstract class BaseAuth<AM extends AuthMap> {
|
|
3
|
+
private __authUsers;
|
|
4
|
+
constructor(authUsers: AuthUsers<AM>);
|
|
5
|
+
free(): void;
|
|
6
|
+
notSetYet(): void;
|
|
7
|
+
notAllowed(): void;
|
|
8
|
+
isUserAuth<T extends UserType<AM>>(type: T): boolean;
|
|
9
|
+
getUserAuth<T extends UserType<AM>>(type: T): NonNullable<AuthUsers<AM>[T]>;
|
|
10
|
+
getUsersAuth<const T extends readonly UserType<AM>[]>(types: T): { [I in keyof T]: InstanceType<AM[T[I]]> | null; };
|
|
11
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseAuth = void 0;
|
|
4
|
+
// helpers
|
|
5
|
+
const helpers_1 = require("../helpers");
|
|
6
|
+
class BaseAuth {
|
|
7
|
+
constructor(authUsers) {
|
|
8
|
+
this.__authUsers = authUsers;
|
|
9
|
+
}
|
|
10
|
+
free() {
|
|
11
|
+
(0, helpers_1.printWarning)('auth', 'free access');
|
|
12
|
+
}
|
|
13
|
+
notSetYet() {
|
|
14
|
+
(0, helpers_1.printWarning)('auth', 'auth not set yet');
|
|
15
|
+
}
|
|
16
|
+
notAllowed() {
|
|
17
|
+
helpers_1.AppError.ThrowUnauthorized();
|
|
18
|
+
}
|
|
19
|
+
isUserAuth(type) {
|
|
20
|
+
return !!this.__authUsers[type];
|
|
21
|
+
}
|
|
22
|
+
getUserAuth(type) {
|
|
23
|
+
const user = this.__authUsers[type];
|
|
24
|
+
if (!user)
|
|
25
|
+
helpers_1.AppError.ThrowUnauthorized();
|
|
26
|
+
return user;
|
|
27
|
+
}
|
|
28
|
+
getUsersAuth(types) {
|
|
29
|
+
const users = types.map((type) => this.__authUsers[type]);
|
|
30
|
+
if (users.every((user) => !user))
|
|
31
|
+
helpers_1.AppError.ThrowUnauthorized();
|
|
32
|
+
return users;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.BaseAuth = BaseAuth;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./access-token.class"), exports);
|
|
18
|
+
__exportStar(require("./auth.helpers"), exports);
|
|
19
|
+
__exportStar(require("./auth.types"), exports);
|
|
20
|
+
__exportStar(require("./base-auth.class"), exports);
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import { Db } from '../database';
|
|
2
|
-
type
|
|
3
|
-
|
|
2
|
+
type Now = {
|
|
3
|
+
year: number;
|
|
4
|
+
yearStr: string;
|
|
5
|
+
month: number;
|
|
6
|
+
monthStr: string;
|
|
7
|
+
day: number;
|
|
8
|
+
dayStr: string;
|
|
9
|
+
hour: number;
|
|
10
|
+
hourStr: string;
|
|
11
|
+
minute: number;
|
|
12
|
+
minuteStr: string;
|
|
13
|
+
};
|
|
14
|
+
type Timezone = 'UTC' | 'America/Argentina/Buenos_Aires';
|
|
15
|
+
type Task = (db: Db, now: Now) => Promise<void>;
|
|
4
16
|
type ScheduleConfig = {
|
|
5
17
|
expression: string;
|
|
6
18
|
timezone: Timezone;
|
|
@@ -10,6 +22,7 @@ type ScheduleConfig = {
|
|
|
10
22
|
export declare abstract class Job {
|
|
11
23
|
static Schedule(config: ScheduleConfig): void;
|
|
12
24
|
private static __Run;
|
|
25
|
+
private static __GetNow;
|
|
13
26
|
}
|
|
14
27
|
export interface JobCtor {
|
|
15
28
|
Init(): void;
|
|
@@ -9,13 +9,14 @@ const database_1 = require("../database");
|
|
|
9
9
|
class Job {
|
|
10
10
|
static Schedule(config) {
|
|
11
11
|
const { expression, timezone, task, runOnInit = false } = config;
|
|
12
|
-
node_cron_1.default.schedule(expression, () => this.__Run(task), { timezone, runOnInit });
|
|
12
|
+
node_cron_1.default.schedule(expression, () => this.__Run(timezone, task), { timezone, runOnInit });
|
|
13
13
|
}
|
|
14
|
-
static async __Run(task) {
|
|
14
|
+
static async __Run(timezone, task) {
|
|
15
15
|
const tx = await (0, database_1.getDbClient)().transaction();
|
|
16
16
|
const db = new database_1.Db(tx);
|
|
17
|
+
const now = this.__GetNow(timezone);
|
|
17
18
|
try {
|
|
18
|
-
await task(db);
|
|
19
|
+
await task(db, now);
|
|
19
20
|
await tx.commit();
|
|
20
21
|
}
|
|
21
22
|
catch (err) {
|
|
@@ -23,5 +24,36 @@ class Job {
|
|
|
23
24
|
throw err;
|
|
24
25
|
}
|
|
25
26
|
}
|
|
27
|
+
static __GetNow(timezone) {
|
|
28
|
+
const today = new Date();
|
|
29
|
+
const parts = new Intl.DateTimeFormat(undefined, {
|
|
30
|
+
timeZone: timezone,
|
|
31
|
+
year: 'numeric',
|
|
32
|
+
month: 'numeric',
|
|
33
|
+
day: 'numeric',
|
|
34
|
+
hour: 'numeric',
|
|
35
|
+
minute: 'numeric',
|
|
36
|
+
hour12: false,
|
|
37
|
+
}).formatToParts(today);
|
|
38
|
+
const getNum = (type) => Number(parts.find((p) => p.type === type).value);
|
|
39
|
+
const pad = (num) => String(num).padStart(2, '0');
|
|
40
|
+
const year = getNum('year');
|
|
41
|
+
const month = getNum('month');
|
|
42
|
+
const day = getNum('day');
|
|
43
|
+
const hour = getNum('hour');
|
|
44
|
+
const minute = getNum('minute');
|
|
45
|
+
return {
|
|
46
|
+
year,
|
|
47
|
+
yearStr: String(year),
|
|
48
|
+
month,
|
|
49
|
+
monthStr: pad(month),
|
|
50
|
+
day,
|
|
51
|
+
dayStr: pad(day),
|
|
52
|
+
hour,
|
|
53
|
+
hourStr: pad(hour),
|
|
54
|
+
minute,
|
|
55
|
+
minuteStr: pad(minute),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
26
58
|
}
|
|
27
59
|
exports.Job = Job;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
exports.startServer = void 0;
|
|
18
18
|
var main_1 = require("./main");
|
|
19
19
|
Object.defineProperty(exports, "startServer", { enumerable: true, get: function () { return main_1.startServer; } });
|
|
20
|
-
__exportStar(require("./
|
|
20
|
+
__exportStar(require("./auth"), exports);
|
|
21
21
|
__exportStar(require("./database"), exports);
|
|
22
22
|
__exportStar(require("./helpers"), exports);
|
|
23
23
|
__exportStar(require("./resources"), exports);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { BaseAuth } from '../
|
|
3
|
-
import type { AuthMap, AuthUsers } from '../
|
|
2
|
+
import { BaseAuth } from '../auth';
|
|
3
|
+
import type { AuthMap, AuthUsers } from '../auth/auth.types';
|
|
4
4
|
import type { RouteValidator as Validator, RouteValidate as Validate } from '../validator/validator.types';
|
|
5
5
|
import type { SetRouteArgs, AuthConfig } from './router.types';
|
|
6
6
|
type ApiMethod = 'get' | 'post' | 'put' | 'patch' | 'delete';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseAuth } from '../
|
|
2
|
-
import type { AuthMap, AuthUsers } from '../
|
|
1
|
+
import { BaseAuth } from '../auth';
|
|
2
|
+
import type { AuthMap, AuthUsers } from '../auth/auth.types';
|
|
3
3
|
import type { RouteValidator, RouteValidate } from '../validator/validator.types';
|
|
4
4
|
import type { Controller, AuthConfig } from './router.types';
|
|
5
5
|
export declare function callController<V extends RouteValidator, AM extends AuthMap, AU extends AuthUsers<AM>, BA extends BaseAuth<AM>>(controller: Controller<V, AM, BA>, validate: RouteValidate<V>, appVersion: string, authConfig: AuthConfig<AM, AU, BA>): (req: Req, res: Res) => Promise<void>;
|
|
@@ -7,8 +7,8 @@ const helpers_1 = require("../helpers");
|
|
|
7
7
|
const pangea_helpers_1 = require("pangea-helpers");
|
|
8
8
|
// database
|
|
9
9
|
const database_1 = require("../database");
|
|
10
|
-
//
|
|
11
|
-
const
|
|
10
|
+
// auth
|
|
11
|
+
const auth_1 = require("../auth");
|
|
12
12
|
// validator
|
|
13
13
|
const validate_request_1 = require("../validator/validate-request");
|
|
14
14
|
function callController(controller, validate, appVersion, authConfig) {
|
|
@@ -24,7 +24,7 @@ function callController(controller, validate, appVersion, authConfig) {
|
|
|
24
24
|
const db = new database_1.Db(tx);
|
|
25
25
|
let result;
|
|
26
26
|
try {
|
|
27
|
-
const authUsers = await (0,
|
|
27
|
+
const authUsers = await (0, auth_1.getUsersFromToken)(headers.authorization, db, accessToken, authMap);
|
|
28
28
|
const auth = new authCtor(authUsers);
|
|
29
29
|
result = await controller(ctx, db, auth);
|
|
30
30
|
await tx.commit();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseAuth, AccessToken } from '../
|
|
2
|
-
import type { AuthMap, AuthUsers, AuthCtor } from '../
|
|
1
|
+
import { BaseAuth, AccessToken } from '../auth';
|
|
2
|
+
import type { AuthMap, AuthUsers, AuthCtor } from '../auth/auth.types';
|
|
3
3
|
import type { RouteValidator } from '../validator/validator.types';
|
|
4
4
|
export type Middleware = (req: Req, res: Res, next: Next) => void;
|
|
5
5
|
export type Controller<V extends RouteValidator, AM extends AuthMap, BA extends BaseAuth<AM>> = (ctx: Ctx<V>, db: Db, auth: BA) => unknown;
|