Skip to content

Commit dce807e

Browse files
author
Josh Cain
committed
feat: include new device setting
1 parent d7617e8 commit dce807e

File tree

11 files changed

+444
-0
lines changed

11 files changed

+444
-0
lines changed

src/context/directory/handlers/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import organizations from './organizations';
1919
import triggers from './triggers';
2020
import attackProtection from './attackProtection';
2121
import riskAssessments from './riskAssessments';
22+
import riskAssessmentsNewDevice from './riskAssessmentsNewDevice';
2223
import branding from './branding';
2324
import phoneProviders from './phoneProvider';
2425
import logStreams from './logStreams';
@@ -71,6 +72,7 @@ const directoryHandlers: {
7172
triggers,
7273
attackProtection,
7374
riskAssessments,
75+
riskAssessmentsNewDevice,
7476
branding,
7577
phoneProviders,
7678
logStreams,
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import path from 'path';
2+
import fs from 'fs-extra';
3+
import { constants } from '../../../tools';
4+
import { dumpJSON, existsMustBeDir, loadJSON } from '../../../utils';
5+
import { DirectoryHandler } from '.';
6+
import DirectoryContext from '..';
7+
import { ParsedAsset, Asset } from '../../../types';
8+
9+
type ParsedRiskAssessmentsNewDevice = ParsedAsset<'riskAssessmentsNewDevice', Asset>;
10+
11+
function parse(context: DirectoryContext): ParsedRiskAssessmentsNewDevice {
12+
const riskAssessmentsDirectory = path.join(
13+
context.filePath,
14+
constants.RISK_ASSESSMENTS_DIRECTORY
15+
);
16+
const newDeviceFile = path.join(riskAssessmentsDirectory, 'new-device.json');
17+
18+
if (!existsMustBeDir(riskAssessmentsDirectory)) {
19+
return { riskAssessmentsNewDevice: null };
20+
}
21+
22+
const riskAssessmentsNewDevice = loadJSON(newDeviceFile, {
23+
mappings: context.mappings,
24+
disableKeywordReplacement: context.disableKeywordReplacement,
25+
});
26+
27+
return {
28+
riskAssessmentsNewDevice,
29+
};
30+
}
31+
32+
async function dump(context: DirectoryContext): Promise<void> {
33+
const { riskAssessmentsNewDevice } = context.assets;
34+
35+
if (!riskAssessmentsNewDevice) return;
36+
37+
const riskAssessmentsDirectory = path.join(
38+
context.filePath,
39+
constants.RISK_ASSESSMENTS_DIRECTORY
40+
);
41+
const newDeviceFile = path.join(riskAssessmentsDirectory, 'new-device.json');
42+
43+
fs.ensureDirSync(riskAssessmentsDirectory);
44+
dumpJSON(newDeviceFile, riskAssessmentsNewDevice);
45+
}
46+
47+
const riskAssessmentsNewDeviceHandler: DirectoryHandler<ParsedRiskAssessmentsNewDevice> = {
48+
parse,
49+
dump,
50+
};
51+
52+
export default riskAssessmentsNewDeviceHandler;

src/context/yaml/handlers/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import actions from './actions';
1919
import triggers from './triggers';
2020
import attackProtection from './attackProtection';
2121
import riskAssessments from './riskAssessments';
22+
import riskAssessmentsNewDevice from './riskAssessmentsNewDevice';
2223
import branding from './branding';
2324
import phoneProviders from './phoneProvider';
2425
import logStreams from './logStreams';
@@ -69,6 +70,7 @@ const yamlHandlers: { [key in AssetTypes]: YAMLHandler<{ [key: string]: unknown
6970
triggers,
7071
attackProtection,
7172
riskAssessments,
73+
riskAssessmentsNewDevice,
7274
branding,
7375
phoneProviders,
7476
logStreams,
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { YAMLHandler } from '.';
2+
import YAMLContext from '..';
3+
import { Asset, ParsedAsset } from '../../../types';
4+
5+
type ParsedRiskAssessmentsNewDevice = ParsedAsset<'riskAssessmentsNewDevice', Asset>;
6+
7+
async function parse(context: YAMLContext): Promise<ParsedRiskAssessmentsNewDevice> {
8+
const { riskAssessmentsNewDevice } = context.assets;
9+
10+
if (!riskAssessmentsNewDevice) return { riskAssessmentsNewDevice: null };
11+
12+
return {
13+
riskAssessmentsNewDevice,
14+
};
15+
}
16+
17+
async function dump(context: YAMLContext): Promise<ParsedRiskAssessmentsNewDevice> {
18+
const { riskAssessmentsNewDevice } = context.assets;
19+
20+
if (!riskAssessmentsNewDevice) return { riskAssessmentsNewDevice: null };
21+
22+
return {
23+
riskAssessmentsNewDevice,
24+
};
25+
}
26+
27+
const riskAssessmentsNewDeviceHandler: YAMLHandler<ParsedRiskAssessmentsNewDevice> = {
28+
parse: parse,
29+
dump: dump,
30+
};
31+
32+
export default riskAssessmentsNewDeviceHandler;

src/tools/auth0/handlers/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import * as triggers from './triggers';
2525
import * as organizations from './organizations';
2626
import * as attackProtection from './attackProtection';
2727
import * as riskAssessments from './riskAssessments';
28+
import * as riskAssessmentsNewDevice from './riskAssessmentsNewDevice';
2829
import * as logStreams from './logStreams';
2930
import * as customDomains from './customDomains';
3031
import * as themes from './themes';
@@ -68,6 +69,7 @@ const auth0ApiHandlers: { [key in AssetTypes]: any } = {
6869
organizations,
6970
attackProtection,
7071
riskAssessments,
72+
riskAssessmentsNewDevice,
7173
logStreams,
7274
customDomains,
7375
themes,
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import DefaultAPIHandler from './default';
2+
import { Assets } from '../../../types';
3+
4+
export const schema = {
5+
type: 'object',
6+
properties: {
7+
remember_for: {
8+
type: 'number',
9+
description: 'Length of time to remember devices for, in days.',
10+
},
11+
},
12+
required: ['remember_for'],
13+
};
14+
15+
export type RiskAssessmentsNewDeviceSettings = {
16+
remember_for: number;
17+
};
18+
19+
export default class RiskAssessmentsNewDeviceHandler extends DefaultAPIHandler {
20+
existing: RiskAssessmentsNewDeviceSettings | null;
21+
22+
constructor(config: DefaultAPIHandler) {
23+
super({
24+
...config,
25+
type: 'riskAssessmentsNewDevice',
26+
});
27+
}
28+
29+
async getType(): Promise<RiskAssessmentsNewDeviceSettings> {
30+
if (this.existing) {
31+
return this.existing;
32+
}
33+
34+
try {
35+
const { data } = await this.client.riskAssessments.getNewDeviceSettings();
36+
this.existing = data;
37+
return data;
38+
} catch (err) {
39+
if (err.statusCode === 404) return { remember_for: 0 };
40+
throw err;
41+
}
42+
}
43+
44+
async processChanges(assets: Assets): Promise<void> {
45+
const { riskAssessmentsNewDevice } = assets;
46+
47+
// Non-existing section means it doesn't need to be processed
48+
if (!riskAssessmentsNewDevice) {
49+
return;
50+
}
51+
52+
try {
53+
// Validate that remember_for property exists
54+
const settings: RiskAssessmentsNewDeviceSettings = {
55+
remember_for: riskAssessmentsNewDevice.remember_for as number,
56+
};
57+
58+
await this.client.riskAssessments.updateNewDeviceSettings(settings);
59+
this.updated += 1;
60+
this.didUpdate(settings);
61+
} catch (err) {
62+
throw err;
63+
}
64+
}
65+
}

src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export type Assets = Partial<{
9696
actions: Action[] | null;
9797
attackProtection: AttackProtection | null;
9898
riskAssessments: Asset | null;
99+
riskAssessmentsNewDevice: Asset | null;
99100
branding:
100101
| (Asset & {
101102
templates?: { template: string; body: string }[] | null;
@@ -178,6 +179,7 @@ export type AssetTypes =
178179
| 'triggers'
179180
| 'attackProtection'
180181
| 'riskAssessments'
182+
| 'riskAssessmentsNewDevice'
181183
| 'branding'
182184
| 'phoneProviders'
183185
| 'logStreams'
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import path from 'path';
2+
import { expect } from 'chai';
3+
import Context from '../../../src/context/directory';
4+
import { cleanThenMkdir, createDir, mockMgmtClient, testDataDir } from '../../utils';
5+
import handler from '../../../src/context/directory/handlers/riskAssessmentsNewDevice';
6+
import { loadJSON } from '../../../src/utils';
7+
8+
describe('#directory context risk-assessments new-device', () => {
9+
it('should replace keywords', async () => {
10+
const files = {
11+
'risk-assessments': {
12+
'settings.json': '{"enabled": true}',
13+
'new-device.json': '{"remember_for": @@REMEMBER_FOR_DAYS@@}',
14+
},
15+
};
16+
17+
const repoDir = path.join(testDataDir, 'directory', 'riskAssessmentsNewDevice1');
18+
createDir(repoDir, files);
19+
20+
const config = {
21+
AUTH0_INPUT_FILE: repoDir,
22+
AUTH0_KEYWORD_REPLACE_MAPPINGS: {
23+
REMEMBER_FOR_DAYS: 30,
24+
},
25+
};
26+
27+
const context = new Context(config, mockMgmtClient());
28+
await context.loadAssetsFromLocal();
29+
30+
const target = {
31+
remember_for: 30,
32+
};
33+
34+
expect(context.assets.riskAssessmentsNewDevice).to.deep.equal(target);
35+
});
36+
37+
it('should process risk-assessments new-device', async () => {
38+
const files = {
39+
'risk-assessments': {
40+
'settings.json': '{"enabled": true}',
41+
'new-device.json': '{"remember_for": 30}',
42+
},
43+
};
44+
45+
const repoDir = path.join(testDataDir, 'directory', 'riskAssessmentsNewDevice2');
46+
createDir(repoDir, files);
47+
48+
const config = { AUTH0_INPUT_FILE: repoDir };
49+
const context = new Context(config, mockMgmtClient());
50+
await context.loadAssetsFromLocal();
51+
52+
const target = {
53+
remember_for: 30,
54+
};
55+
56+
expect(context.assets.riskAssessmentsNewDevice).to.deep.equal(target);
57+
});
58+
59+
it('should process risk-assessments new-device with zero value', async () => {
60+
const files = {
61+
'risk-assessments': {
62+
'settings.json': '{"enabled": true}',
63+
'new-device.json': '{"remember_for": 0}',
64+
},
65+
};
66+
67+
const repoDir = path.join(testDataDir, 'directory', 'riskAssessmentsNewDevice3');
68+
createDir(repoDir, files);
69+
70+
const config = { AUTH0_INPUT_FILE: repoDir };
71+
const context = new Context(config, mockMgmtClient());
72+
await context.loadAssetsFromLocal();
73+
74+
const target = {
75+
remember_for: 0,
76+
};
77+
78+
expect(context.assets.riskAssessmentsNewDevice).to.deep.equal(target);
79+
});
80+
81+
it('should process risk-assessments new-device with large value', async () => {
82+
const files = {
83+
'risk-assessments': {
84+
'settings.json': '{"enabled": true}',
85+
'new-device.json': '{"remember_for": 365}',
86+
},
87+
};
88+
89+
const repoDir = path.join(testDataDir, 'directory', 'riskAssessmentsNewDevice4');
90+
createDir(repoDir, files);
91+
92+
const config = { AUTH0_INPUT_FILE: repoDir };
93+
const context = new Context(config, mockMgmtClient());
94+
await context.loadAssetsFromLocal();
95+
96+
const target = {
97+
remember_for: 365,
98+
};
99+
100+
expect(context.assets.riskAssessmentsNewDevice).to.deep.equal(target);
101+
});
102+
103+
it('should dump risk-assessments new-device', async () => {
104+
const dir = path.join(testDataDir, 'directory', 'riskAssessmentsNewDeviceDump');
105+
cleanThenMkdir(dir);
106+
const context = new Context({ AUTH0_INPUT_FILE: dir }, mockMgmtClient());
107+
108+
context.assets.riskAssessmentsNewDevice = {
109+
remember_for: 90,
110+
};
111+
112+
await handler.dump(context);
113+
const riskAssessmentsFolder = path.join(dir, 'risk-assessments');
114+
115+
expect(loadJSON(path.join(riskAssessmentsFolder, 'new-device.json'))).to.deep.equal(
116+
context.assets.riskAssessmentsNewDevice
117+
);
118+
});
119+
120+
it('should not create files if riskAssessmentsNewDevice is null', async () => {
121+
const dir = path.join(testDataDir, 'directory', 'riskAssessmentsNewDeviceNull');
122+
cleanThenMkdir(dir);
123+
const context = new Context({ AUTH0_INPUT_FILE: dir }, mockMgmtClient());
124+
125+
context.assets.riskAssessmentsNewDevice = null;
126+
127+
await handler.dump(context);
128+
const riskAssessmentsFolder = path.join(dir, 'risk-assessments');
129+
130+
expect(() => loadJSON(path.join(riskAssessmentsFolder, 'new-device.json'))).to.throw();
131+
});
132+
});

test/context/yaml/context.test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,9 @@ describe('#YAML context validation', () => {
275275
riskAssessments: {
276276
enabled: false,
277277
},
278+
riskAssessmentsNewDevice: {
279+
remember_for: 30,
280+
},
278281
rules: [],
279282
hooks: [],
280283
actions: [],
@@ -408,6 +411,9 @@ describe('#YAML context validation', () => {
408411
riskAssessments: {
409412
enabled: false,
410413
},
414+
riskAssessmentsNewDevice: {
415+
remember_for: 30,
416+
},
411417
rules: [],
412418
hooks: [],
413419
actions: [],
@@ -542,6 +548,9 @@ describe('#YAML context validation', () => {
542548
riskAssessments: {
543549
enabled: false,
544550
},
551+
riskAssessmentsNewDevice: {
552+
remember_for: 30,
553+
},
545554
rules: [],
546555
hooks: [],
547556
actions: [],

0 commit comments

Comments
 (0)