@naturalcycles/nodejs-lib 12.80.3 → 12.81.0

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/index.d.ts CHANGED
@@ -72,5 +72,6 @@ export * from './validation/joi/joi.shared.schemas';
72
72
  export * from './validation/joi/joi.validation.error';
73
73
  export * from './validation/joi/joi.validation.util';
74
74
  export * from './script';
75
+ export * from './jwt/jwt.service';
75
76
  export type { GlobbyOptions, FastGlobOptions, ValidationErrorItem, AnySchema, Got, AfterResponseHook, BeforeErrorHook, BeforeRequestHook, };
76
77
  export { globby, fastGlob, RequestError, TimeoutError, Ajv };
package/dist/index.js CHANGED
@@ -77,3 +77,4 @@ tslib_1.__exportStar(require("./validation/joi/joi.shared.schemas"), exports);
77
77
  tslib_1.__exportStar(require("./validation/joi/joi.validation.error"), exports);
78
78
  tslib_1.__exportStar(require("./validation/joi/joi.validation.util"), exports);
79
79
  tslib_1.__exportStar(require("./script"), exports);
80
+ tslib_1.__exportStar(require("./jwt/jwt.service"), exports);
@@ -0,0 +1,55 @@
1
+ /// <reference types="node" />
2
+ import { AnyObject, ErrorData, JWTString } from '@naturalcycles/js-lib';
3
+ import type { Algorithm, VerifyOptions, JwtHeader, SignOptions } from 'jsonwebtoken';
4
+ import * as jsonwebtoken from 'jsonwebtoken';
5
+ import { AnySchemaTyped } from '../validation/joi/joi.model';
6
+ export { jsonwebtoken };
7
+ export type { Algorithm, VerifyOptions, SignOptions, JwtHeader };
8
+ export interface JWTServiceCfg {
9
+ /**
10
+ * Public key is required to Verify incoming tokens.
11
+ * Optional if you only want to Decode or Sign.
12
+ */
13
+ publicKey?: string | Buffer;
14
+ /**
15
+ * Private key is required to Sign (create) outgoing tokens.
16
+ * Optional if you only want to Decode or Verify.
17
+ */
18
+ privateKey?: string | Buffer;
19
+ /**
20
+ * Recommended: ES256
21
+ */
22
+ algorithm: Algorithm;
23
+ /**
24
+ * If provided - will be applied to every Sign operation.
25
+ */
26
+ signOptions?: SignOptions;
27
+ /**
28
+ * If provided - will be applied to every Sign operation.
29
+ */
30
+ verifyOptions?: VerifyOptions;
31
+ /**
32
+ * If set - errors thrown from this service will be extended
33
+ * with this errorData (in err.data)
34
+ */
35
+ errorData?: ErrorData;
36
+ }
37
+ /**
38
+ * Wraps popular `jsonwebtoken` library.
39
+ * You should create one instance of JWTService for each pair of private/public key.
40
+ *
41
+ * Generate key pair like this:
42
+ * openssl ecparam -name secp256k1 -genkey -noout -out key.pem
43
+ * openssl ec -in key.pem -pubout > key.pub.pem
44
+ */
45
+ export declare class JWTService {
46
+ cfg: JWTServiceCfg;
47
+ constructor(cfg: JWTServiceCfg);
48
+ sign<T extends AnyObject>(payload: T, schema?: AnySchemaTyped<T>, opt?: SignOptions): JWTString;
49
+ verify<T extends AnyObject>(token: JWTString, schema?: AnySchemaTyped<T>, opt?: VerifyOptions): T;
50
+ decode<T extends AnyObject>(token: JWTString, schema?: AnySchemaTyped<T>): {
51
+ header: JwtHeader;
52
+ payload: T;
53
+ signature: string;
54
+ };
55
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JWTService = exports.jsonwebtoken = void 0;
4
+ const js_lib_1 = require("@naturalcycles/js-lib");
5
+ const jsonwebtoken = require("jsonwebtoken");
6
+ exports.jsonwebtoken = jsonwebtoken;
7
+ const joi_shared_schemas_1 = require("../validation/joi/joi.shared.schemas");
8
+ const joi_validation_util_1 = require("../validation/joi/joi.validation.util");
9
+ // todo: define JWTError and list possible options
10
+ /**
11
+ * Wraps popular `jsonwebtoken` library.
12
+ * You should create one instance of JWTService for each pair of private/public key.
13
+ *
14
+ * Generate key pair like this:
15
+ * openssl ecparam -name secp256k1 -genkey -noout -out key.pem
16
+ * openssl ec -in key.pem -pubout > key.pub.pem
17
+ */
18
+ class JWTService {
19
+ constructor(cfg) {
20
+ this.cfg = cfg;
21
+ }
22
+ sign(payload, schema, opt = {}) {
23
+ (0, js_lib_1._assert)(this.cfg.privateKey, 'JWTService: privateKey is required to be able to verify, but not provided');
24
+ if (schema) {
25
+ (0, joi_validation_util_1.validate)(payload, schema);
26
+ }
27
+ return jsonwebtoken.sign(payload, this.cfg.privateKey, {
28
+ algorithm: this.cfg.algorithm,
29
+ noTimestamp: true,
30
+ ...this.cfg.signOptions,
31
+ ...opt,
32
+ });
33
+ }
34
+ verify(token, schema, opt = {}) {
35
+ (0, js_lib_1._assert)(this.cfg.publicKey, 'JWTService: publicKey is required to be able to verify, but not provided');
36
+ try {
37
+ const data = jsonwebtoken.verify(token, this.cfg.publicKey, {
38
+ algorithms: [this.cfg.algorithm],
39
+ ...this.cfg.verifyOptions,
40
+ ...opt,
41
+ });
42
+ if (schema) {
43
+ (0, joi_validation_util_1.validate)(data, schema);
44
+ }
45
+ return data;
46
+ }
47
+ catch (err) {
48
+ if (this.cfg.errorData) {
49
+ (0, js_lib_1._typeCast)(err);
50
+ (0, js_lib_1._errorDataAppend)(err, {
51
+ ...this.cfg.errorData,
52
+ });
53
+ }
54
+ throw err;
55
+ }
56
+ }
57
+ decode(token, schema) {
58
+ const data = jsonwebtoken.decode(token, {
59
+ complete: true,
60
+ });
61
+ (0, js_lib_1._assert)(data, 'invalid token, decoded value is null', {
62
+ ...this.cfg.errorData,
63
+ });
64
+ (0, joi_validation_util_1.validate)(data.payload, schema || joi_shared_schemas_1.anyObjectSchema);
65
+ return data;
66
+ }
67
+ }
68
+ exports.JWTService = JWTService;
@@ -1,10 +1,10 @@
1
1
  export interface IDebug {
2
2
  (namespace: string): IDebugger;
3
- coerce: (val: any) => any;
4
- disable: () => string;
5
- enable: (namespaces: string) => void;
6
- enabled: (namespaces: string) => boolean;
7
- log: (...args: any[]) => any;
3
+ coerce(val: any): any;
4
+ disable(): string;
5
+ enable(namespaces: string): void;
6
+ enabled(namespaces: string): boolean;
7
+ log(...args: any[]): any;
8
8
  names: RegExp[];
9
9
  skips: RegExp[];
10
10
  formatters: DebugFormatters;
@@ -16,8 +16,8 @@ export interface IDebugger {
16
16
  (...args: any[]): void;
17
17
  color: string;
18
18
  enabled: boolean;
19
- log: (...args: any[]) => any;
19
+ log(...args: any[]): any;
20
20
  namespace: string;
21
- destroy: () => boolean;
21
+ destroy(): boolean;
22
22
  }
23
23
  export declare const Debug: IDebug;
@@ -75,7 +75,7 @@ export interface TransformLogProgressOptions<IN = any> extends TransformOptions
75
75
  *
76
76
  * chunk is undefined for "final" stats, otherwise is defined.
77
77
  */
78
- extra?: (chunk: IN | undefined, index: number) => AnyObject;
78
+ extra?(chunk: IN | undefined, index: number): AnyObject;
79
79
  /**
80
80
  * If specified - will multiply the counter by this number.
81
81
  * Useful e.g when using `transformBuffer({ batchSize: 500 })`, so
@@ -29,7 +29,7 @@ export interface TransformMapOptions<IN = any, OUT = IN> {
29
29
  * If defined - will be called on every error happening in the stream.
30
30
  * Called BEFORE observable will emit error (unless skipErrors is set to true).
31
31
  */
32
- onError?: (err: Error, input: IN) => any;
32
+ onError?(err: Error, input: IN): any;
33
33
  /**
34
34
  * Progress metric
35
35
  *
@@ -27,7 +27,7 @@ export interface TransformMapSyncOptions<IN = any, OUT = IN> {
27
27
  * If defined - will be called on every error happening in the stream.
28
28
  * Called BEFORE observable will emit error (unless skipErrors is set to true).
29
29
  */
30
- onError?: (err: Error, input: IN) => any;
30
+ onError?(err: Error, input: IN): any;
31
31
  /**
32
32
  * Progress metric
33
33
  *
@@ -106,7 +106,7 @@ function createError(value, err, objectName) {
106
106
  const tokens = [];
107
107
  const objectId = (0, js_lib_1._isObject)(value) ? value['id'] : undefined;
108
108
  if (objectId || objectName) {
109
- objectName = objectName || value?.constructor?.name;
109
+ objectName ||= value?.constructor?.name;
110
110
  tokens.push('Invalid ' + [objectName, objectId].filter(Boolean).join('.'));
111
111
  }
112
112
  const annotation = err.annotate(stripColors);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
- "version": "12.80.3",
3
+ "version": "12.81.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "docs-serve": "vuepress dev docs",
@@ -15,6 +15,7 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@naturalcycles/js-lib": "^14.0.0",
18
+ "@types/jsonwebtoken": "^8.5.9",
18
19
  "@types/through2-concurrent": "^2.0.0",
19
20
  "ajv": "^8.6.2",
20
21
  "ajv-formats": "^2.1.0",
@@ -31,6 +32,7 @@
31
32
  "globby": "^11.0.0",
32
33
  "got": "^11.0.1",
33
34
  "joi": "17.4.2",
35
+ "jsonwebtoken": "^8.5.1",
34
36
  "lru-cache": "^7.4.0",
35
37
  "move-file": "^2.0.0",
36
38
  "through2-concurrent": "^2.0.0",
package/src/index.ts CHANGED
@@ -72,6 +72,7 @@ export * from './validation/joi/joi.shared.schemas'
72
72
  export * from './validation/joi/joi.validation.error'
73
73
  export * from './validation/joi/joi.validation.util'
74
74
  export * from './script'
75
+ export * from './jwt/jwt.service'
75
76
 
76
77
  export type {
77
78
  GlobbyOptions,
@@ -0,0 +1,143 @@
1
+ import {
2
+ _assert,
3
+ _errorDataAppend,
4
+ _typeCast,
5
+ AnyObject,
6
+ ErrorData,
7
+ JWTString,
8
+ } from '@naturalcycles/js-lib'
9
+ import type { Algorithm, VerifyOptions, JwtHeader, SignOptions } from 'jsonwebtoken'
10
+ import * as jsonwebtoken from 'jsonwebtoken'
11
+ import { AnySchemaTyped } from '../validation/joi/joi.model'
12
+ import { anyObjectSchema } from '../validation/joi/joi.shared.schemas'
13
+ import { validate } from '../validation/joi/joi.validation.util'
14
+ export { jsonwebtoken }
15
+ export type { Algorithm, VerifyOptions, SignOptions, JwtHeader }
16
+
17
+ export interface JWTServiceCfg {
18
+ /**
19
+ * Public key is required to Verify incoming tokens.
20
+ * Optional if you only want to Decode or Sign.
21
+ */
22
+ publicKey?: string | Buffer
23
+ /**
24
+ * Private key is required to Sign (create) outgoing tokens.
25
+ * Optional if you only want to Decode or Verify.
26
+ */
27
+ privateKey?: string | Buffer
28
+
29
+ /**
30
+ * Recommended: ES256
31
+ */
32
+ algorithm: Algorithm
33
+
34
+ /**
35
+ * If provided - will be applied to every Sign operation.
36
+ */
37
+ signOptions?: SignOptions
38
+
39
+ /**
40
+ * If provided - will be applied to every Sign operation.
41
+ */
42
+ verifyOptions?: VerifyOptions
43
+
44
+ /**
45
+ * If set - errors thrown from this service will be extended
46
+ * with this errorData (in err.data)
47
+ */
48
+ errorData?: ErrorData
49
+ }
50
+
51
+ // todo: define JWTError and list possible options
52
+
53
+ /**
54
+ * Wraps popular `jsonwebtoken` library.
55
+ * You should create one instance of JWTService for each pair of private/public key.
56
+ *
57
+ * Generate key pair like this:
58
+ * openssl ecparam -name secp256k1 -genkey -noout -out key.pem
59
+ * openssl ec -in key.pem -pubout > key.pub.pem
60
+ */
61
+ export class JWTService {
62
+ constructor(public cfg: JWTServiceCfg) {}
63
+
64
+ sign<T extends AnyObject>(
65
+ payload: T,
66
+ schema?: AnySchemaTyped<T>,
67
+ opt: SignOptions = {},
68
+ ): JWTString {
69
+ _assert(
70
+ this.cfg.privateKey,
71
+ 'JWTService: privateKey is required to be able to verify, but not provided',
72
+ )
73
+
74
+ if (schema) {
75
+ validate(payload, schema)
76
+ }
77
+
78
+ return jsonwebtoken.sign(payload, this.cfg.privateKey, {
79
+ algorithm: this.cfg.algorithm,
80
+ noTimestamp: true,
81
+ ...this.cfg.signOptions,
82
+ ...opt,
83
+ })
84
+ }
85
+
86
+ verify<T extends AnyObject>(
87
+ token: JWTString,
88
+ schema?: AnySchemaTyped<T>,
89
+ opt: VerifyOptions = {},
90
+ ): T {
91
+ _assert(
92
+ this.cfg.publicKey,
93
+ 'JWTService: publicKey is required to be able to verify, but not provided',
94
+ )
95
+
96
+ try {
97
+ const data = jsonwebtoken.verify(token, this.cfg.publicKey, {
98
+ algorithms: [this.cfg.algorithm],
99
+ ...this.cfg.verifyOptions,
100
+ ...opt,
101
+ }) as T
102
+
103
+ if (schema) {
104
+ validate(data, schema)
105
+ }
106
+
107
+ return data
108
+ } catch (err) {
109
+ if (this.cfg.errorData) {
110
+ _typeCast<Error>(err)
111
+ _errorDataAppend(err, {
112
+ ...this.cfg.errorData,
113
+ })
114
+ }
115
+ throw err
116
+ }
117
+ }
118
+
119
+ decode<T extends AnyObject>(
120
+ token: JWTString,
121
+ schema?: AnySchemaTyped<T>,
122
+ ): {
123
+ header: JwtHeader
124
+ payload: T
125
+ signature: string
126
+ } {
127
+ const data = jsonwebtoken.decode(token, {
128
+ complete: true,
129
+ }) as {
130
+ header: JwtHeader
131
+ payload: T
132
+ signature: string
133
+ } | null
134
+
135
+ _assert(data, 'invalid token, decoded value is null', {
136
+ ...this.cfg.errorData,
137
+ })
138
+
139
+ validate(data.payload, schema || anyObjectSchema)
140
+
141
+ return data
142
+ }
143
+ }
package/src/log/debug.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  // Types based on @types/debug
2
2
  export interface IDebug {
3
3
  (namespace: string): IDebugger
4
- coerce: (val: any) => any
5
- disable: () => string
6
- enable: (namespaces: string) => void
7
- enabled: (namespaces: string) => boolean
8
- log: (...args: any[]) => any
4
+ coerce(val: any): any
5
+ disable(): string
6
+ enable(namespaces: string): void
7
+ enabled(namespaces: string): boolean
8
+ log(...args: any[]): any
9
9
 
10
10
  names: RegExp[]
11
11
  skips: RegExp[]
@@ -23,9 +23,9 @@ export interface IDebugger {
23
23
 
24
24
  color: string
25
25
  enabled: boolean
26
- log: (...args: any[]) => any
26
+ log(...args: any[]): any
27
27
  namespace: string
28
- destroy: () => boolean
28
+ destroy(): boolean
29
29
  // extend: (namespace: string, delimiter?: string) => IDebugger
30
30
  }
31
31
 
@@ -100,7 +100,7 @@ export interface TransformLogProgressOptions<IN = any> extends TransformOptions
100
100
  *
101
101
  * chunk is undefined for "final" stats, otherwise is defined.
102
102
  */
103
- extra?: (chunk: IN | undefined, index: number) => AnyObject
103
+ extra?(chunk: IN | undefined, index: number): AnyObject
104
104
 
105
105
  /**
106
106
  * If specified - will multiply the counter by this number.
@@ -48,7 +48,7 @@ export interface TransformMapOptions<IN = any, OUT = IN> {
48
48
  * If defined - will be called on every error happening in the stream.
49
49
  * Called BEFORE observable will emit error (unless skipErrors is set to true).
50
50
  */
51
- onError?: (err: Error, input: IN) => any
51
+ onError?(err: Error, input: IN): any
52
52
 
53
53
  /**
54
54
  * Progress metric
@@ -43,7 +43,7 @@ export interface TransformMapSyncOptions<IN = any, OUT = IN> {
43
43
  * If defined - will be called on every error happening in the stream.
44
44
  * Called BEFORE observable will emit error (unless skipErrors is set to true).
45
45
  */
46
- onError?: (err: Error, input: IN) => any
46
+ onError?(err: Error, input: IN): any
47
47
 
48
48
  /**
49
49
  * Progress metric
@@ -139,7 +139,7 @@ function createError(value: any, err: ValidationError, objectName?: string): Joi
139
139
  const objectId = _isObject(value) ? (value['id'] as string) : undefined
140
140
 
141
141
  if (objectId || objectName) {
142
- objectName = objectName || value?.constructor?.name
142
+ objectName ||= value?.constructor?.name
143
143
 
144
144
  tokens.push('Invalid ' + [objectName, objectId].filter(Boolean).join('.'))
145
145
  }