@fintekkers/ledger-models 0.4.29 → 0.4.31
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/node/wrappers/models/position/position_matcher.d.ts +4 -2
- package/node/wrappers/models/position/position_matcher.js +5 -3
- package/node/wrappers/models/position/position_matcher.test.js +55 -5
- package/node/wrappers/models/position/position_matcher.test.ts +48 -1
- package/node/wrappers/models/position/position_matcher.ts +5 -3
- package/node/wrappers/models/utils/requestcontext.auth.test.js +21 -6
- package/node/wrappers/models/utils/requestcontext.auth.test.js.map +1 -1
- package/node/wrappers/models/utils/requestcontext.auth.test.ts +24 -6
- package/node/wrappers/models/utils/requestcontext.d.ts +18 -12
- package/node/wrappers/models/utils/requestcontext.js +28 -28
- package/node/wrappers/models/utils/requestcontext.js.map +1 -1
- package/node/wrappers/models/utils/requestcontext.test.js +15 -3
- package/node/wrappers/models/utils/requestcontext.test.js.map +1 -1
- package/node/wrappers/models/utils/requestcontext.test.ts +17 -3
- package/node/wrappers/models/utils/requestcontext.ts +31 -29
- package/node/wrappers/services/apikey.credentials.test.d.ts +1 -1
- package/node/wrappers/services/apikey.credentials.test.js +14 -12
- package/node/wrappers/services/apikey.credentials.test.js.map +1 -1
- package/node/wrappers/services/apikey.credentials.test.ts +15 -13
- package/node/wrappers/services/apikey.test.js +1 -1
- package/node/wrappers/services/apikey.test.js.map +1 -1
- package/node/wrappers/services/apikey.test.ts +1 -1
- package/node/wrappers/services/portfolio-service/PortfolioService.d.ts +2 -1
- package/node/wrappers/services/portfolio-service/PortfolioService.js +8 -4
- package/node/wrappers/services/portfolio-service/PortfolioService.js.map +1 -1
- package/node/wrappers/services/portfolio-service/PortfolioService.ts +8 -4
- package/node/wrappers/services/position-service/PositionService.js +4 -3
- package/node/wrappers/services/position-service/PositionService.js.map +1 -1
- package/node/wrappers/services/position-service/PositionService.ts +4 -3
- package/node/wrappers/services/price-service/PriceService.js +4 -3
- package/node/wrappers/services/price-service/PriceService.js.map +1 -1
- package/node/wrappers/services/price-service/PriceService.ts +4 -3
- package/node/wrappers/services/security-service/SecurityService.js +4 -3
- package/node/wrappers/services/security-service/SecurityService.js.map +1 -1
- package/node/wrappers/services/security-service/SecurityService.ts +4 -3
- package/node/wrappers/services/serviceaddress.clients.test.d.ts +9 -0
- package/node/wrappers/services/serviceaddress.clients.test.js +181 -0
- package/node/wrappers/services/serviceaddress.clients.test.js.map +1 -0
- package/node/wrappers/services/serviceaddress.clients.test.ts +176 -0
- package/node/wrappers/services/transaction-service/TransactionService.js +4 -3
- package/node/wrappers/services/transaction-service/TransactionService.js.map +1 -1
- package/node/wrappers/services/transaction-service/TransactionService.ts +4 -3
- package/node/wrappers/util/link-resolver.d.ts +1 -1
- package/node/wrappers/util/link-resolver.js +10 -9
- package/node/wrappers/util/link-resolver.js.map +1 -1
- package/node/wrappers/util/link-resolver.ts +11 -10
- package/node/wrappers/util/serviceaddress.d.ts +47 -0
- package/node/wrappers/util/serviceaddress.js +132 -0
- package/node/wrappers/util/serviceaddress.js.map +1 -0
- package/node/wrappers/util/serviceaddress.test.d.ts +6 -0
- package/node/wrappers/util/serviceaddress.test.js +76 -0
- package/node/wrappers/util/serviceaddress.test.js.map +1 -0
- package/node/wrappers/util/serviceaddress.test.ts +83 -0
- package/node/wrappers/util/serviceaddress.ts +141 -0
- package/package.json +1 -1
|
@@ -15,8 +15,10 @@ export interface FilterableRow {
|
|
|
15
15
|
* ASSET_CLASS with EQUALS / NOT_EQUALS uses the shared assetClassMatches
|
|
16
16
|
* rule, so a group code such as FIXED_INCOME matches its members and labels;
|
|
17
17
|
* every other field compares exactly. A null or undefined stored value never
|
|
18
|
-
* throws
|
|
19
|
-
*
|
|
18
|
+
* throws and drops the row for every operator, except ASSET_CLASS with
|
|
19
|
+
* NOT_EQUALS, which keeps it (LM-281). The null check runs before the
|
|
20
|
+
* ASSET_CLASS branch, so it handles that asset-class exception itself
|
|
21
|
+
* (LM-284). An unknown operator matches nothing. Errors raised by row.getField
|
|
20
22
|
* propagate (a row represents an absent value by returning null).
|
|
21
23
|
*/
|
|
22
24
|
export declare function matches(field: FieldProto, operator: PositionFilterOperator, filterValue: any, storedValue: any): boolean;
|
|
@@ -9,13 +9,15 @@ const product_hierarchy_1 = require("../security/product_hierarchy");
|
|
|
9
9
|
* ASSET_CLASS with EQUALS / NOT_EQUALS uses the shared assetClassMatches
|
|
10
10
|
* rule, so a group code such as FIXED_INCOME matches its members and labels;
|
|
11
11
|
* every other field compares exactly. A null or undefined stored value never
|
|
12
|
-
* throws
|
|
13
|
-
*
|
|
12
|
+
* throws and drops the row for every operator, except ASSET_CLASS with
|
|
13
|
+
* NOT_EQUALS, which keeps it (LM-281). The null check runs before the
|
|
14
|
+
* ASSET_CLASS branch, so it handles that asset-class exception itself
|
|
15
|
+
* (LM-284). An unknown operator matches nothing. Errors raised by row.getField
|
|
14
16
|
* propagate (a row represents an absent value by returning null).
|
|
15
17
|
*/
|
|
16
18
|
function matches(field, operator, filterValue, storedValue) {
|
|
17
19
|
if (storedValue === null || storedValue === undefined) {
|
|
18
|
-
return operator === position_util_pb_1.PositionFilterOperator.NOT_EQUALS;
|
|
20
|
+
return field === field_pb_1.FieldProto.ASSET_CLASS && operator === position_util_pb_1.PositionFilterOperator.NOT_EQUALS;
|
|
19
21
|
}
|
|
20
22
|
if (field === field_pb_1.FieldProto.ASSET_CLASS &&
|
|
21
23
|
(operator === position_util_pb_1.PositionFilterOperator.EQUALS ||
|
|
@@ -1,19 +1,46 @@
|
|
|
1
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
29
|
/**
|
|
3
30
|
* LM-281: the JS filter helper matches Java's PositionFilter row for row.
|
|
4
31
|
*
|
|
5
32
|
* ASSET_CLASS EQUALS / NOT_EQUALS use the shared assetClassMatches rule;
|
|
6
33
|
* every other field compares exactly. A null stored value never throws.
|
|
7
34
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
const fs = __importStar(require("fs"));
|
|
36
|
+
const path = __importStar(require("path"));
|
|
12
37
|
const field_pb_1 = require("../../../fintekkers/models/position/field_pb");
|
|
13
38
|
const position_util_pb_1 = require("../../../fintekkers/models/position/position_util_pb");
|
|
14
39
|
const security_pb_1 = require("../../../fintekkers/models/security/security_pb");
|
|
15
40
|
const security_1 = __importDefault(require("../security/security"));
|
|
16
41
|
const position_matcher_1 = require("./position_matcher");
|
|
42
|
+
const PROTOS = path.resolve(__dirname, '../../../../../ledger-models-protos');
|
|
43
|
+
const nullCases = JSON.parse(fs.readFileSync(path.join(PROTOS, 'fixtures/position_filter_null_cases.json'), 'utf-8')).cases;
|
|
17
44
|
function securityRow(assetClass) {
|
|
18
45
|
const proto = new security_pb_1.SecurityProto();
|
|
19
46
|
proto.setAssetClass(assetClass);
|
|
@@ -58,7 +85,26 @@ describe('position_matcher', () => {
|
|
|
58
85
|
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.MATURITY_DATE, position_util_pb_1.PositionFilterOperator.MORE_THAN, 1, 2)).toBe(true);
|
|
59
86
|
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.MATURITY_DATE, position_util_pb_1.PositionFilterOperator.MORE_THAN, 2, 1)).toBe(false);
|
|
60
87
|
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.PORTFOLIO_NAME, position_util_pb_1.PositionFilterOperator.EQUALS, 'a', null)).toBe(false);
|
|
61
|
-
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.PORTFOLIO_NAME, position_util_pb_1.PositionFilterOperator.NOT_EQUALS, 'a', null)).toBe(
|
|
88
|
+
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.PORTFOLIO_NAME, position_util_pb_1.PositionFilterOperator.NOT_EQUALS, 'a', null)).toBe(false);
|
|
89
|
+
});
|
|
90
|
+
// LM-284: NOT_EQUALS drops a null on every field but ASSET_CLASS. Cases
|
|
91
|
+
// come from ledger-models-protos/fixtures/position_filter_null_cases.json,
|
|
92
|
+
// shared with the Java, Python and Rust tests.
|
|
93
|
+
test('the shared null-cases fixture has its cases', () => {
|
|
94
|
+
expect(nullCases.length).toBeGreaterThanOrEqual(7);
|
|
95
|
+
});
|
|
96
|
+
test.each(nullCases)('$field $operator $filter on null -> $expected', (c) => {
|
|
97
|
+
const field = field_pb_1.FieldProto[c.field];
|
|
98
|
+
const operator = position_util_pb_1.PositionFilterOperator[c.operator];
|
|
99
|
+
expect(field).toBeDefined();
|
|
100
|
+
expect(operator).toBeDefined();
|
|
101
|
+
expect((0, position_matcher_1.matches)(field, operator, c.filter, null)).toBe(c.expected);
|
|
102
|
+
});
|
|
103
|
+
test('filterRows NOT_EQUALS drops a row with a null on another field', () => {
|
|
104
|
+
const filters = [
|
|
105
|
+
{ field: field_pb_1.FieldProto.PORTFOLIO_NAME, operator: position_util_pb_1.PositionFilterOperator.NOT_EQUALS, value: 'a' },
|
|
106
|
+
];
|
|
107
|
+
expect((0, position_matcher_1.filterRows)([stubRow(null)], filters)).toEqual([]);
|
|
62
108
|
});
|
|
63
109
|
});
|
|
64
110
|
describe('the published (compiled) position_matcher.js', () => {
|
|
@@ -74,4 +120,8 @@ describe('the published (compiled) position_matcher.js', () => {
|
|
|
74
120
|
const kept = compiled.filterRows(rows, assetClassFilter(position_util_pb_1.PositionFilterOperator.EQUALS));
|
|
75
121
|
expect(assetClasses(kept)).toEqual(['RATES']);
|
|
76
122
|
});
|
|
123
|
+
test('has the LM-284 null rule', () => {
|
|
124
|
+
expect(compiled.matches(field_pb_1.FieldProto.PORTFOLIO_NAME, position_util_pb_1.PositionFilterOperator.NOT_EQUALS, 'a', null)).toBe(false);
|
|
125
|
+
expect(compiled.matches(field_pb_1.FieldProto.ASSET_CLASS, position_util_pb_1.PositionFilterOperator.NOT_EQUALS, 'FIXED_INCOME', null)).toBe(true);
|
|
126
|
+
});
|
|
77
127
|
});
|
|
@@ -4,12 +4,28 @@
|
|
|
4
4
|
* ASSET_CLASS EQUALS / NOT_EQUALS use the shared assetClassMatches rule;
|
|
5
5
|
* every other field compares exactly. A null stored value never throws.
|
|
6
6
|
*/
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
|
|
7
10
|
import { FieldProto } from '../../../fintekkers/models/position/field_pb';
|
|
8
11
|
import { PositionFilterOperator } from '../../../fintekkers/models/position/position_util_pb';
|
|
9
12
|
import { SecurityProto } from '../../../fintekkers/models/security/security_pb';
|
|
10
13
|
import Security from '../security/security';
|
|
11
14
|
import { FilterableRow, FilterSpec, filterRows, matches } from './position_matcher';
|
|
12
15
|
|
|
16
|
+
const PROTOS = path.resolve(__dirname, '../../../../../ledger-models-protos');
|
|
17
|
+
|
|
18
|
+
interface NullCase {
|
|
19
|
+
field: string;
|
|
20
|
+
operator: string;
|
|
21
|
+
filter: string;
|
|
22
|
+
expected: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const nullCases: NullCase[] = JSON.parse(
|
|
26
|
+
fs.readFileSync(path.join(PROTOS, 'fixtures/position_filter_null_cases.json'), 'utf-8'),
|
|
27
|
+
).cases;
|
|
28
|
+
|
|
13
29
|
function securityRow(assetClass: string): Security {
|
|
14
30
|
const proto = new SecurityProto();
|
|
15
31
|
proto.setAssetClass(assetClass);
|
|
@@ -61,7 +77,29 @@ describe('position_matcher', () => {
|
|
|
61
77
|
expect(matches(FieldProto.MATURITY_DATE, PositionFilterOperator.MORE_THAN, 1, 2)).toBe(true);
|
|
62
78
|
expect(matches(FieldProto.MATURITY_DATE, PositionFilterOperator.MORE_THAN, 2, 1)).toBe(false);
|
|
63
79
|
expect(matches(FieldProto.PORTFOLIO_NAME, PositionFilterOperator.EQUALS, 'a', null)).toBe(false);
|
|
64
|
-
expect(matches(FieldProto.PORTFOLIO_NAME, PositionFilterOperator.NOT_EQUALS, 'a', null)).toBe(
|
|
80
|
+
expect(matches(FieldProto.PORTFOLIO_NAME, PositionFilterOperator.NOT_EQUALS, 'a', null)).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// LM-284: NOT_EQUALS drops a null on every field but ASSET_CLASS. Cases
|
|
84
|
+
// come from ledger-models-protos/fixtures/position_filter_null_cases.json,
|
|
85
|
+
// shared with the Java, Python and Rust tests.
|
|
86
|
+
test('the shared null-cases fixture has its cases', () => {
|
|
87
|
+
expect(nullCases.length).toBeGreaterThanOrEqual(7);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test.each(nullCases)('$field $operator $filter on null -> $expected', (c) => {
|
|
91
|
+
const field = FieldProto[c.field as keyof typeof FieldProto];
|
|
92
|
+
const operator = PositionFilterOperator[c.operator as keyof typeof PositionFilterOperator];
|
|
93
|
+
expect(field).toBeDefined();
|
|
94
|
+
expect(operator).toBeDefined();
|
|
95
|
+
expect(matches(field, operator, c.filter, null)).toBe(c.expected);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('filterRows NOT_EQUALS drops a row with a null on another field', () => {
|
|
99
|
+
const filters: FilterSpec[] = [
|
|
100
|
+
{ field: FieldProto.PORTFOLIO_NAME, operator: PositionFilterOperator.NOT_EQUALS, value: 'a' },
|
|
101
|
+
];
|
|
102
|
+
expect(filterRows([stubRow(null)], filters)).toEqual([]);
|
|
65
103
|
});
|
|
66
104
|
});
|
|
67
105
|
|
|
@@ -93,4 +131,13 @@ describe('the published (compiled) position_matcher.js', () => {
|
|
|
93
131
|
const kept = compiled.filterRows(rows, assetClassFilter(PositionFilterOperator.EQUALS));
|
|
94
132
|
expect(assetClasses(kept)).toEqual(['RATES']);
|
|
95
133
|
});
|
|
134
|
+
|
|
135
|
+
test('has the LM-284 null rule', () => {
|
|
136
|
+
expect(
|
|
137
|
+
compiled.matches(FieldProto.PORTFOLIO_NAME, PositionFilterOperator.NOT_EQUALS, 'a', null),
|
|
138
|
+
).toBe(false);
|
|
139
|
+
expect(
|
|
140
|
+
compiled.matches(FieldProto.ASSET_CLASS, PositionFilterOperator.NOT_EQUALS, 'FIXED_INCOME', null),
|
|
141
|
+
).toBe(true);
|
|
142
|
+
});
|
|
96
143
|
});
|
|
@@ -19,8 +19,10 @@ export interface FilterableRow {
|
|
|
19
19
|
* ASSET_CLASS with EQUALS / NOT_EQUALS uses the shared assetClassMatches
|
|
20
20
|
* rule, so a group code such as FIXED_INCOME matches its members and labels;
|
|
21
21
|
* every other field compares exactly. A null or undefined stored value never
|
|
22
|
-
* throws
|
|
23
|
-
*
|
|
22
|
+
* throws and drops the row for every operator, except ASSET_CLASS with
|
|
23
|
+
* NOT_EQUALS, which keeps it (LM-281). The null check runs before the
|
|
24
|
+
* ASSET_CLASS branch, so it handles that asset-class exception itself
|
|
25
|
+
* (LM-284). An unknown operator matches nothing. Errors raised by row.getField
|
|
24
26
|
* propagate (a row represents an absent value by returning null).
|
|
25
27
|
*/
|
|
26
28
|
export function matches(
|
|
@@ -30,7 +32,7 @@ export function matches(
|
|
|
30
32
|
storedValue: any,
|
|
31
33
|
): boolean {
|
|
32
34
|
if (storedValue === null || storedValue === undefined) {
|
|
33
|
-
return operator === PositionFilterOperator.NOT_EQUALS;
|
|
35
|
+
return field === FieldProto.ASSET_CLASS && operator === PositionFilterOperator.NOT_EQUALS;
|
|
34
36
|
}
|
|
35
37
|
if (
|
|
36
38
|
field === FieldProto.ASSET_CLASS &&
|
|
@@ -33,6 +33,9 @@ const grpc = __importStar(require("@grpc/grpc-js"));
|
|
|
33
33
|
const requestcontext_1 = __importStar(require("./requestcontext"));
|
|
34
34
|
const savedApiUrl = process.env.API_URL;
|
|
35
35
|
const savedApiKey = process.env.API_KEY;
|
|
36
|
+
// Variables the lookup reads before API_URL; the host may set them.
|
|
37
|
+
const SHADOWING = ['BROKER_HOST', 'LEDGER_SERVICE_HOST', 'LEDGER_SERVICE_PORT'];
|
|
38
|
+
const savedShadowing = SHADOWING.map((k) => process.env[k]);
|
|
36
39
|
function restoreEnv(name, value) {
|
|
37
40
|
if (value === undefined) {
|
|
38
41
|
delete process.env[name];
|
|
@@ -44,10 +47,12 @@ function restoreEnv(name, value) {
|
|
|
44
47
|
beforeEach(() => {
|
|
45
48
|
restoreEnv('API_URL', undefined);
|
|
46
49
|
restoreEnv('API_KEY', undefined);
|
|
50
|
+
SHADOWING.forEach((k) => restoreEnv(k, undefined));
|
|
47
51
|
});
|
|
48
52
|
afterEach(() => {
|
|
49
53
|
restoreEnv('API_URL', savedApiUrl);
|
|
50
54
|
restoreEnv('API_KEY', savedApiKey);
|
|
55
|
+
SHADOWING.forEach((k, i) => restoreEnv(k, savedShadowing[i]));
|
|
51
56
|
jest.restoreAllMocks();
|
|
52
57
|
});
|
|
53
58
|
describe('EnvConfig.apiURL', () => {
|
|
@@ -59,8 +64,8 @@ describe('EnvConfig.apiURL', () => {
|
|
|
59
64
|
process.env.API_URL = 'localhost';
|
|
60
65
|
expect(requestcontext_1.default.apiURL).toBe('localhost:8082');
|
|
61
66
|
});
|
|
62
|
-
test('defaults to
|
|
63
|
-
expect(requestcontext_1.default.apiURL).toBe('
|
|
67
|
+
test('defaults to localhost:8082 when API_URL is unset', () => {
|
|
68
|
+
expect(requestcontext_1.default.apiURL).toBe('localhost:8082');
|
|
64
69
|
});
|
|
65
70
|
});
|
|
66
71
|
describe('EnvConfig.apiKey', () => {
|
|
@@ -82,7 +87,15 @@ describe('EnvConfig.apiCredentials', () => {
|
|
|
82
87
|
expect(insecure).toHaveBeenCalledTimes(1);
|
|
83
88
|
expect(ssl).not.toHaveBeenCalled();
|
|
84
89
|
});
|
|
85
|
-
test('uses
|
|
90
|
+
test('uses insecure credentials when API_URL is unset (localhost:8082)', () => {
|
|
91
|
+
const insecure = jest.spyOn(grpc.credentials, 'createInsecure');
|
|
92
|
+
const ssl = jest.spyOn(grpc.credentials, 'createSsl');
|
|
93
|
+
requestcontext_1.default.apiCredentials;
|
|
94
|
+
expect(insecure).toHaveBeenCalledTimes(1);
|
|
95
|
+
expect(ssl).not.toHaveBeenCalled();
|
|
96
|
+
});
|
|
97
|
+
test('uses SSL credentials for a remote API_URL', () => {
|
|
98
|
+
process.env.API_URL = 'myhost.example.com';
|
|
86
99
|
const insecure = jest.spyOn(grpc.credentials, 'createInsecure');
|
|
87
100
|
const ssl = jest.spyOn(grpc.credentials, 'createSsl');
|
|
88
101
|
requestcontext_1.default.apiCredentials;
|
|
@@ -92,13 +105,14 @@ describe('EnvConfig.apiCredentials', () => {
|
|
|
92
105
|
});
|
|
93
106
|
describe('EnvConfig.getAuthenticatedCredentials', () => {
|
|
94
107
|
test('metadata generator injects x-api-key', () => {
|
|
108
|
+
process.env.API_URL = 'myhost.example.com';
|
|
95
109
|
const generatorSpy = jest.spyOn(grpc.credentials, 'createFromMetadataGenerator');
|
|
96
110
|
const creds = requestcontext_1.default.getAuthenticatedCredentials('k');
|
|
97
111
|
expect(creds).toBeInstanceOf(grpc.ChannelCredentials);
|
|
98
112
|
expect(generatorSpy).toHaveBeenCalledTimes(1);
|
|
99
113
|
const generator = generatorSpy.mock.calls[0][0];
|
|
100
114
|
const callback = jest.fn();
|
|
101
|
-
generator({ service_url: 'https://
|
|
115
|
+
generator({ service_url: 'https://myhost.example.com:8082' }, callback);
|
|
102
116
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
103
117
|
const [err, metadata] = callback.mock.calls[0];
|
|
104
118
|
expect(err).toBeNull();
|
|
@@ -127,6 +141,7 @@ describe('EnvConfig.getAuthenticatedCredentials', () => {
|
|
|
127
141
|
jest.spyOn(console, 'error').mockImplementation(() => { }),
|
|
128
142
|
];
|
|
129
143
|
const generatorSpy = jest.spyOn(grpc.credentials, 'createFromMetadataGenerator');
|
|
144
|
+
process.env.API_URL = 'myhost.example.com';
|
|
130
145
|
requestcontext_1.default.getAuthenticatedCredentials(secret);
|
|
131
146
|
generatorSpy.mock.calls[0][0]({ service_url: '' }, () => { });
|
|
132
147
|
process.env.API_URL = 'localhost:80';
|
|
@@ -148,8 +163,8 @@ describe('EnvConfig.getAuthenticatedClientOptions', () => {
|
|
|
148
163
|
expect(ssl).not.toHaveBeenCalled();
|
|
149
164
|
expect(interceptors).toHaveLength(1);
|
|
150
165
|
});
|
|
151
|
-
test('uses SSL channel for
|
|
152
|
-
process.env.API_URL = '
|
|
166
|
+
test('uses SSL channel for a remote host', () => {
|
|
167
|
+
process.env.API_URL = 'myhost.example.com';
|
|
153
168
|
const insecure = jest.spyOn(grpc.credentials, 'createInsecure');
|
|
154
169
|
const ssl = jest.spyOn(grpc.credentials, 'createSsl');
|
|
155
170
|
const { interceptors } = requestcontext_1.default.getAuthenticatedClientOptions('k');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestcontext.auth.test.js","sourceRoot":"","sources":["requestcontext.auth.test.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,oDAAsC;AACtC,mEAAuE;AAEvE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;AACxC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"requestcontext.auth.test.js","sourceRoot":"","sources":["requestcontext.auth.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,9 @@ import EnvConfig, { InsecureChannelAuthError } from './requestcontext';
|
|
|
10
10
|
|
|
11
11
|
const savedApiUrl = process.env.API_URL;
|
|
12
12
|
const savedApiKey = process.env.API_KEY;
|
|
13
|
+
// Variables the lookup reads before API_URL; the host may set them.
|
|
14
|
+
const SHADOWING = ['BROKER_HOST', 'LEDGER_SERVICE_HOST', 'LEDGER_SERVICE_PORT'];
|
|
15
|
+
const savedShadowing = SHADOWING.map((k) => process.env[k]);
|
|
13
16
|
|
|
14
17
|
function restoreEnv(name: string, value: string | undefined) {
|
|
15
18
|
if (value === undefined) {
|
|
@@ -22,11 +25,13 @@ function restoreEnv(name: string, value: string | undefined) {
|
|
|
22
25
|
beforeEach(() => {
|
|
23
26
|
restoreEnv('API_URL', undefined);
|
|
24
27
|
restoreEnv('API_KEY', undefined);
|
|
28
|
+
SHADOWING.forEach((k) => restoreEnv(k, undefined));
|
|
25
29
|
});
|
|
26
30
|
|
|
27
31
|
afterEach(() => {
|
|
28
32
|
restoreEnv('API_URL', savedApiUrl);
|
|
29
33
|
restoreEnv('API_KEY', savedApiKey);
|
|
34
|
+
SHADOWING.forEach((k, i) => restoreEnv(k, savedShadowing[i]));
|
|
30
35
|
jest.restoreAllMocks();
|
|
31
36
|
});
|
|
32
37
|
|
|
@@ -41,8 +46,8 @@ describe('EnvConfig.apiURL', () => {
|
|
|
41
46
|
expect(EnvConfig.apiURL).toBe('localhost:8082');
|
|
42
47
|
});
|
|
43
48
|
|
|
44
|
-
test('defaults to
|
|
45
|
-
expect(EnvConfig.apiURL).toBe('
|
|
49
|
+
test('defaults to localhost:8082 when API_URL is unset', () => {
|
|
50
|
+
expect(EnvConfig.apiURL).toBe('localhost:8082');
|
|
46
51
|
});
|
|
47
52
|
});
|
|
48
53
|
|
|
@@ -70,7 +75,18 @@ describe('EnvConfig.apiCredentials', () => {
|
|
|
70
75
|
expect(ssl).not.toHaveBeenCalled();
|
|
71
76
|
});
|
|
72
77
|
|
|
73
|
-
test('uses
|
|
78
|
+
test('uses insecure credentials when API_URL is unset (localhost:8082)', () => {
|
|
79
|
+
const insecure = jest.spyOn(grpc.credentials, 'createInsecure');
|
|
80
|
+
const ssl = jest.spyOn(grpc.credentials, 'createSsl');
|
|
81
|
+
|
|
82
|
+
EnvConfig.apiCredentials;
|
|
83
|
+
|
|
84
|
+
expect(insecure).toHaveBeenCalledTimes(1);
|
|
85
|
+
expect(ssl).not.toHaveBeenCalled();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('uses SSL credentials for a remote API_URL', () => {
|
|
89
|
+
process.env.API_URL = 'myhost.example.com';
|
|
74
90
|
const insecure = jest.spyOn(grpc.credentials, 'createInsecure');
|
|
75
91
|
const ssl = jest.spyOn(grpc.credentials, 'createSsl');
|
|
76
92
|
|
|
@@ -83,6 +99,7 @@ describe('EnvConfig.apiCredentials', () => {
|
|
|
83
99
|
|
|
84
100
|
describe('EnvConfig.getAuthenticatedCredentials', () => {
|
|
85
101
|
test('metadata generator injects x-api-key', () => {
|
|
102
|
+
process.env.API_URL = 'myhost.example.com';
|
|
86
103
|
const generatorSpy = jest.spyOn(grpc.credentials, 'createFromMetadataGenerator');
|
|
87
104
|
|
|
88
105
|
const creds = EnvConfig.getAuthenticatedCredentials('k');
|
|
@@ -92,7 +109,7 @@ describe('EnvConfig.getAuthenticatedCredentials', () => {
|
|
|
92
109
|
|
|
93
110
|
const generator = generatorSpy.mock.calls[0][0];
|
|
94
111
|
const callback = jest.fn();
|
|
95
|
-
generator({ service_url: 'https://
|
|
112
|
+
generator({ service_url: 'https://myhost.example.com:8082' }, callback);
|
|
96
113
|
|
|
97
114
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
98
115
|
const [err, metadata] = callback.mock.calls[0];
|
|
@@ -129,6 +146,7 @@ describe('EnvConfig.getAuthenticatedCredentials', () => {
|
|
|
129
146
|
];
|
|
130
147
|
const generatorSpy = jest.spyOn(grpc.credentials, 'createFromMetadataGenerator');
|
|
131
148
|
|
|
149
|
+
process.env.API_URL = 'myhost.example.com';
|
|
132
150
|
EnvConfig.getAuthenticatedCredentials(secret);
|
|
133
151
|
generatorSpy.mock.calls[0][0]({ service_url: '' }, () => {});
|
|
134
152
|
process.env.API_URL = 'localhost:80';
|
|
@@ -155,8 +173,8 @@ describe('EnvConfig.getAuthenticatedClientOptions', () => {
|
|
|
155
173
|
expect(interceptors).toHaveLength(1);
|
|
156
174
|
});
|
|
157
175
|
|
|
158
|
-
test('uses SSL channel for
|
|
159
|
-
process.env.API_URL = '
|
|
176
|
+
test('uses SSL channel for a remote host', () => {
|
|
177
|
+
process.env.API_URL = 'myhost.example.com';
|
|
160
178
|
const insecure = jest.spyOn(grpc.credentials, 'createInsecure');
|
|
161
179
|
const ssl = jest.spyOn(grpc.credentials, 'createSsl');
|
|
162
180
|
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import * as grpc from '@grpc/grpc-js';
|
|
2
|
+
import { Service } from '../../util/serviceaddress';
|
|
2
3
|
declare class EnvConfig {
|
|
3
|
-
private static getEnvVar;
|
|
4
4
|
static get apiKey(): string | undefined;
|
|
5
5
|
/**
|
|
6
|
-
* Returns the
|
|
7
|
-
*
|
|
8
|
-
* API_URL
|
|
9
|
-
*
|
|
6
|
+
* Returns the `host:port` of the ledger service, found the same way as
|
|
7
|
+
* every other service: `BROKER_HOST`, then `LEDGER_SERVICE_HOST`/`_PORT`,
|
|
8
|
+
* then `API_URL` (with :8082 unless it carries a port), then
|
|
9
|
+
* localhost:8082. Clients should prefer {@link EnvConfig.urlFor}.
|
|
10
10
|
*/
|
|
11
11
|
static get apiURL(): string;
|
|
12
|
-
|
|
12
|
+
/** Returns the `host:port` a client for `service` connects to. */
|
|
13
|
+
static urlFor(service: Service): string;
|
|
14
|
+
private static isPlaintext;
|
|
15
|
+
/** Channel credentials for {@link EnvConfig.apiURL}. */
|
|
13
16
|
static get apiCredentials(): grpc.ChannelCredentials;
|
|
17
|
+
/** Insecure credentials for a loopback address, SSL otherwise. */
|
|
18
|
+
static credentialsFor(service: Service): grpc.ChannelCredentials;
|
|
14
19
|
private static addApiKey;
|
|
15
20
|
/**
|
|
16
21
|
* Returns SSL channel credentials combined with per-call credentials that
|
|
@@ -21,22 +26,23 @@ declare class EnvConfig {
|
|
|
21
26
|
* {@link EnvConfig.getAuthenticatedClientOptions}, which sends the key via
|
|
22
27
|
* an interceptor instead.
|
|
23
28
|
*
|
|
24
|
-
* @throws {InsecureChannelAuthError} when
|
|
29
|
+
* @throws {InsecureChannelAuthError} when the address of `service` is
|
|
30
|
+
* localhost / 127.0.0.1.
|
|
25
31
|
*/
|
|
26
|
-
static getAuthenticatedCredentials(apiKey: string): grpc.ChannelCredentials;
|
|
32
|
+
static getAuthenticatedCredentials(apiKey: string, service?: Service): grpc.ChannelCredentials;
|
|
27
33
|
/**
|
|
28
|
-
* Returns credentials and interceptors for authenticated calls
|
|
34
|
+
* Returns credentials and interceptors for authenticated calls to `service`.
|
|
29
35
|
* For local (insecure) channels, injects the API key via an interceptor.
|
|
30
36
|
* For remote (SSL) channels, uses {@link EnvConfig.getAuthenticatedCredentials}.
|
|
31
37
|
*/
|
|
32
|
-
static getAuthenticatedClientOptions(apiKey: string): {
|
|
38
|
+
static getAuthenticatedClientOptions(apiKey: string, service?: Service): {
|
|
33
39
|
credentials: grpc.ChannelCredentials;
|
|
34
40
|
interceptors: grpc.Interceptor[];
|
|
35
41
|
};
|
|
36
42
|
}
|
|
37
43
|
/**
|
|
38
|
-
* Thrown by EnvConfig.getAuthenticatedCredentials when
|
|
39
|
-
* insecure (local) channel. The message never includes the API key.
|
|
44
|
+
* Thrown by EnvConfig.getAuthenticatedCredentials when the service address is
|
|
45
|
+
* an insecure (local) channel. The message never includes the API key.
|
|
40
46
|
*/
|
|
41
47
|
export declare class InsecureChannelAuthError extends Error {
|
|
42
48
|
constructor();
|
|
@@ -27,35 +27,34 @@ exports.InsecureChannelAuthError = void 0;
|
|
|
27
27
|
const dotenv = __importStar(require("dotenv"));
|
|
28
28
|
dotenv.config();
|
|
29
29
|
const grpc = __importStar(require("@grpc/grpc-js"));
|
|
30
|
+
const serviceaddress_1 = require("../../util/serviceaddress");
|
|
30
31
|
class EnvConfig {
|
|
31
|
-
static getEnvVar(key, defaultValue) {
|
|
32
|
-
const value = process.env[key];
|
|
33
|
-
if (value === undefined) {
|
|
34
|
-
if (defaultValue === undefined) {
|
|
35
|
-
throw new Error(`Environment variable ${key} is not set.`);
|
|
36
|
-
}
|
|
37
|
-
return defaultValue;
|
|
38
|
-
}
|
|
39
|
-
return value;
|
|
40
|
-
}
|
|
41
32
|
static get apiKey() {
|
|
42
33
|
return process.env['API_KEY'];
|
|
43
34
|
}
|
|
44
35
|
/**
|
|
45
|
-
* Returns the
|
|
46
|
-
*
|
|
47
|
-
* API_URL
|
|
48
|
-
*
|
|
36
|
+
* Returns the `host:port` of the ledger service, found the same way as
|
|
37
|
+
* every other service: `BROKER_HOST`, then `LEDGER_SERVICE_HOST`/`_PORT`,
|
|
38
|
+
* then `API_URL` (with :8082 unless it carries a port), then
|
|
39
|
+
* localhost:8082. Clients should prefer {@link EnvConfig.urlFor}.
|
|
49
40
|
*/
|
|
50
41
|
static get apiURL() {
|
|
51
|
-
|
|
52
|
-
return /:\d+$/.test(base) ? base : base + ':8082';
|
|
42
|
+
return EnvConfig.urlFor(serviceaddress_1.Service.SECURITY);
|
|
53
43
|
}
|
|
54
|
-
|
|
55
|
-
|
|
44
|
+
/** Returns the `host:port` a client for `service` connects to. */
|
|
45
|
+
static urlFor(service) {
|
|
46
|
+
return (0, serviceaddress_1.target)((0, serviceaddress_1.resolve)(service));
|
|
56
47
|
}
|
|
48
|
+
static isPlaintext(service) {
|
|
49
|
+
return (0, serviceaddress_1.resolve)(service).plaintext;
|
|
50
|
+
}
|
|
51
|
+
/** Channel credentials for {@link EnvConfig.apiURL}. */
|
|
57
52
|
static get apiCredentials() {
|
|
58
|
-
|
|
53
|
+
return EnvConfig.credentialsFor(serviceaddress_1.Service.SECURITY);
|
|
54
|
+
}
|
|
55
|
+
/** Insecure credentials for a loopback address, SSL otherwise. */
|
|
56
|
+
static credentialsFor(service) {
|
|
57
|
+
if (EnvConfig.isPlaintext(service)) {
|
|
59
58
|
return grpc.credentials.createInsecure();
|
|
60
59
|
}
|
|
61
60
|
else {
|
|
@@ -74,10 +73,11 @@ class EnvConfig {
|
|
|
74
73
|
* {@link EnvConfig.getAuthenticatedClientOptions}, which sends the key via
|
|
75
74
|
* an interceptor instead.
|
|
76
75
|
*
|
|
77
|
-
* @throws {InsecureChannelAuthError} when
|
|
76
|
+
* @throws {InsecureChannelAuthError} when the address of `service` is
|
|
77
|
+
* localhost / 127.0.0.1.
|
|
78
78
|
*/
|
|
79
|
-
static getAuthenticatedCredentials(apiKey) {
|
|
80
|
-
if (
|
|
79
|
+
static getAuthenticatedCredentials(apiKey, service = serviceaddress_1.Service.SECURITY) {
|
|
80
|
+
if (EnvConfig.isPlaintext(service)) {
|
|
81
81
|
throw new InsecureChannelAuthError();
|
|
82
82
|
}
|
|
83
83
|
const callCreds = grpc.credentials.createFromMetadataGenerator((_params, callback) => {
|
|
@@ -88,12 +88,12 @@ class EnvConfig {
|
|
|
88
88
|
return grpc.credentials.combineChannelCredentials(grpc.credentials.createSsl(), callCreds);
|
|
89
89
|
}
|
|
90
90
|
/**
|
|
91
|
-
* Returns credentials and interceptors for authenticated calls
|
|
91
|
+
* Returns credentials and interceptors for authenticated calls to `service`.
|
|
92
92
|
* For local (insecure) channels, injects the API key via an interceptor.
|
|
93
93
|
* For remote (SSL) channels, uses {@link EnvConfig.getAuthenticatedCredentials}.
|
|
94
94
|
*/
|
|
95
|
-
static getAuthenticatedClientOptions(apiKey) {
|
|
96
|
-
if (
|
|
95
|
+
static getAuthenticatedClientOptions(apiKey, service = serviceaddress_1.Service.SECURITY) {
|
|
96
|
+
if (EnvConfig.isPlaintext(service)) {
|
|
97
97
|
const interceptor = (_options, nextCall) => {
|
|
98
98
|
return new grpc.InterceptingCall(nextCall(_options), {
|
|
99
99
|
start(metadata, listener, next) {
|
|
@@ -105,14 +105,14 @@ class EnvConfig {
|
|
|
105
105
|
return { credentials: grpc.credentials.createInsecure(), interceptors: [interceptor] };
|
|
106
106
|
}
|
|
107
107
|
return {
|
|
108
|
-
credentials: EnvConfig.getAuthenticatedCredentials(apiKey),
|
|
108
|
+
credentials: EnvConfig.getAuthenticatedCredentials(apiKey, service),
|
|
109
109
|
interceptors: []
|
|
110
110
|
};
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
/**
|
|
114
|
-
* Thrown by EnvConfig.getAuthenticatedCredentials when
|
|
115
|
-
* insecure (local) channel. The message never includes the API key.
|
|
114
|
+
* Thrown by EnvConfig.getAuthenticatedCredentials when the service address is
|
|
115
|
+
* an insecure (local) channel. The message never includes the API key.
|
|
116
116
|
*/
|
|
117
117
|
class InsecureChannelAuthError extends Error {
|
|
118
118
|
constructor() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestcontext.js","sourceRoot":"","sources":["requestcontext.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AACjC,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,oDAAsC;AAEtC,
|
|
1
|
+
{"version":3,"file":"requestcontext.js","sourceRoot":"","sources":["requestcontext.ts"],"names":[],"mappings":"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"}
|