-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
127 lines (110 loc) · 3.08 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
const debug = require('debug')('engine:radius');
const { template } = require('artillery/util');
const { promisify } = require('util');
const radclient = promisify(require('radclient'));
const getPort = require('get-port');
const time = require('./lib/time');
/**
* Generate a random identifier for a RADIUS request.
*
* RADIUS request identifiers must be 1 octect (8-bit)
*/
const getRandomIdentifier = () => {
const max = 255;
return Math.floor(Math.random() * Math.floor(max));
};
/**
* Returns a generator function that generates numbers from the
* ephemeral port range.
*/
const randomEphemeralPortRange = (() => {
const from = 49152;
const to = 65535;
const generator = function* (from, to) {
while (true) {
const port = Math.floor(Math.random() * (to - from + 1) + from);
yield port;
}
};
return generator(from, to);
})();
/**
* Gets a free ephemeral port suitable for sending a RADIUS packet.
*/
const getFreeEphemeralPort = async () => {
return getPort({ port: randomEphemeralPortRange });
};
/**
* Performs RADIUS auth request
*/
const authRequest = async (config, ee, context) => {
const options = {
host: context.radius.host,
port: context.radius.port,
localPort: await getFreeEphemeralPort(),
timeout: context.radius.timeout || config.timeout,
retries: context.radius.retries || config.retries
};
debug(`Radclient options: ${JSON.stringify(options)}`);
const packet = {
code: 'Access-Request',
secret: config.secret,
identifier: getRandomIdentifier(),
attributes: [
['User-Name', config.username],
['User-Password', config.password]
]
};
debug(`Radclient packet: ${JSON.stringify(packet)}`);
ee.emit('request');
const startTime = time.getTime();
await radclient(packet, options)
.then((response) => {
const { code } = response;
const delta = time.getDelta(startTime);
ee.emit('response', delta, code, context._uid);
})
.catch((error) => {
const errorMsg = `Auth error: ${error}`;
throw new Error(errorMsg);
});
};
function RADIUSEngine(script, ee, helpers) {
this.script = script;
this.ee = ee;
this.helpers = helpers;
return this;
}
const runStep = async (spec, ee, context) => {
if (spec.auth) {
await authRequest(spec.auth, ee, context);
}
};
const runFlow = async (flow, ee, context) => {
for (const step of flow) await runStep(step, ee, context);
};
RADIUSEngine.prototype.createScenario = function (scenarioSpec, ee) {
const { target: host, radius: config } = this.script.config;
return (context, callback) => {
const { name, flow } = template(scenarioSpec, context);
const radiusContext = {
...context,
radius: {
host,
...config
}
};
ee.emit('started');
debug(`Running scenario ${name}`);
runFlow(flow, ee, radiusContext)
.then(() => {
ee.emit('done');
return callback(null, radiusContext);
})
.catch((error) => {
ee.emit('error', error);
return callback(error, radiusContext);
});
};
};
module.exports = RADIUSEngine;