Skip to content

Commit 7bdedc0

Browse files
committed
API v1.2
1 parent 1e160cb commit 7bdedc0

143 files changed

Lines changed: 70396 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/1.2/api.js

Lines changed: 375 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,375 @@
1+
/*
2+
Fixed DOB and Registration dates to use ISO 8601 standard (yyyy-mm-ddThh:mm:ssZ)
3+
Street numbers range from 1-9999
4+
Add coordinates to location
5+
Add timezone to location
6+
Add uuid to login
7+
Fix AVS number format for CH
8+
Add Norway data
9+
Fix CA postal code format
10+
*/
11+
12+
const mersenne = require('mersenne');
13+
const moment = require('moment');
14+
const crypto = require('crypto');
15+
const YAML = require('yamljs');
16+
const js2xmlparser = require('js2xmlparser');
17+
const converter = require('json-2-csv');
18+
const faker = require('faker');
19+
const version = '1.2';
20+
21+
// Load the datasets if not defined
22+
if (typeof datasets[version] === 'undefined') {
23+
require('./loadDatasets')((data, injectNats) => {
24+
datasets[version] = data;
25+
injects[version] = injectNats;
26+
});
27+
}
28+
29+
const originalFieldList = 'gender, name, location, email,\
30+
login, registered, dob, phone, cell, id, picture, nat';
31+
32+
const originalFieldArray = originalFieldList
33+
.split(',')
34+
.filter((i) => i !== '')
35+
.map((w) => w.trim().toLowerCase());
36+
37+
var Generator = function(options) {
38+
// Check for multiple vals
39+
this.checkOptions(options);
40+
41+
options = options || {};
42+
this.results = Number(options.results);
43+
this.seed = options.seed || '';
44+
this.lego = typeof options.lego !== 'undefined' && options.lego !== 'false' ? true : false;
45+
this.gender = options.gender || null;
46+
this.format = (options.format || options.fmt || 'json').toLowerCase();
47+
this.nat = options.nat || options.nationality || null;
48+
this.noInfo = typeof options.noinfo !== 'undefined' && options.lego !== 'false' ? true : false;
49+
this.page = Number(options.page) || 1;
50+
this.password = options.password;
51+
52+
// Include all fields by default
53+
this.inc = options.inc || originalFieldList;
54+
this.exc = options.exc || '';
55+
56+
this.inc = this.inc.split(',').filter((i) => i !== '').map((w) => w.trim().toLowerCase());
57+
this.exc = this.exc.split(',').filter((i) => i !== '').map((w) => w.trim().toLowerCase());
58+
59+
// Remove exclusions
60+
this.inc = this.inc.filter((w) => this.exc.indexOf(w) === -1);
61+
62+
// Update exclusions list to inverse of inclusions
63+
this.exc = originalFieldArray.filter((w) => this.inc.indexOf(w) === -1);
64+
65+
if (this.nat !== null) {
66+
this.nat = this.nat.split(',').filter((i) => i !== '');
67+
}
68+
69+
if (this.nat !== null) this.nat = uppercaseify(this.nat);
70+
this.nats = this.getNats(); // Returns array of nats
71+
this.constantTime = 1471295130;
72+
this.version = version;
73+
74+
// Sanitize values
75+
if (isNaN(this.results) || this.results < 0 || this.results > settings.maxResults || this.results === '') this.results = 1;
76+
77+
if (this.gender !== 'male' && this.gender !== 'female' || this.seed !== '') {
78+
this.gender = null;
79+
}
80+
81+
if (this.lego) this.nat = 'LEGO';
82+
else if (this.nat !== null && !(this.validNat(this.nat))) this.nat = null;
83+
84+
if (this.seed.length === 18) {
85+
this.nat = this.nats[parseInt(this.seed.slice(-2), 16)];
86+
} else if (this.seed === '') {
87+
this.defaultSeed();
88+
}
89+
90+
if (this.page < 0 || this.page > 10000) this.page = 1;
91+
///////////////////
92+
93+
this.seedRNG();
94+
};
95+
96+
Generator.prototype.generate = function(cb) {
97+
this.results = this.results || 1;
98+
99+
let output = [];
100+
let nat, inject;
101+
102+
for (let i = 0; i < this.results; i++) {
103+
current = {};
104+
nat = this.nat === null ? this.randomNat() : this.nat;
105+
if (Array.isArray(nat)) {
106+
nat = nat[range(0, nat.length-1)];
107+
}
108+
inject = injects[version][nat];
109+
110+
current.gender = this.gender === null ? randomItem(['male', 'female']) : this.gender;
111+
112+
let name = this.randomName(current.gender, nat);
113+
this.include('name', {
114+
title: current.gender === 'male' ? 'mr' : randomItem(datasets[version].common.title),
115+
first: name[0],
116+
last: name[1]
117+
});
118+
119+
let timezone = JSON.parse(randomItem(datasets[version].common.timezones));
120+
this.include('location', {
121+
street: range(1, 9999) + ' ' + randomItem(datasets[version][nat].street),
122+
city: randomItem(datasets[version][nat].cities),
123+
state: randomItem(datasets[version][nat].states),
124+
postcode: range(10000, 99999),
125+
coordinates: {
126+
latitude: faker.address.latitude(),
127+
longitude: faker.address.longitude()
128+
},
129+
timezone
130+
});
131+
132+
this.include('email', name[0] + '.' + name[1].replace(/ /g, '') + '@example.com');
133+
134+
let salt = random(2, 8);
135+
let password = this.password === undefined ? randomItem(datasets[version].common.passwords) : this.genPassword();
136+
this.include('login', {
137+
uuid: faker.random.uuid(),
138+
username: randomItem(datasets[version].common.user1) + randomItem(datasets[version].common.user2) + range(100, 999),
139+
password,
140+
salt: salt,
141+
md5: crypto.createHash('md5').update(password + salt).digest('hex'),
142+
sha1: crypto.createHash('sha1').update(password + salt).digest('hex'),
143+
sha256: crypto.createHash('sha256').update(password + salt).digest('hex')
144+
});
145+
146+
let dob = range(-800000000000, this.constantTime*1000 - 86400000*365*21);
147+
this.include('dob', moment(dob).format('YYYY-MM-DDTHH:mm:ss\\Z'));
148+
this.include('registered', moment(range(1016688461000, this.constantTime*1000)).format('YYYY-MM-DDTHH:mm:ss\\Z'));
149+
150+
let id, genderText
151+
if (nat != 'LEGO') {
152+
id = current.gender == 'male' ? range(0, 99) : range(0, 96);
153+
genderText = current.gender == 'male' ? 'men' : 'women';
154+
} else {
155+
id = range(0, 9);
156+
genderText = 'lego';
157+
}
158+
base = 'https://randomuser.me/api/';
159+
160+
this.include('picture', {
161+
large: base + 'portraits/' + genderText + '/' + id + '.jpg',
162+
medium: base + 'portraits/med/' + genderText + '/' + id + '.jpg',
163+
thumbnail: base + 'portraits/thumb/' + genderText + '/' + id + '.jpg'
164+
});
165+
166+
inject(this.inc, current); // Inject unique fields for nationality
167+
168+
this.include('nat', nat);
169+
170+
// Gender hack - Remove gender if the user doesn't want it in the results
171+
if (this.inc.indexOf('gender') === -1) {
172+
delete current.gender;
173+
}
174+
175+
output.push(current);
176+
}
177+
178+
let json = {
179+
results: output,
180+
info: {
181+
seed: String(this.seed + (this.nat !== null && !Array.isArray(this.nat) ? pad((this.nats.indexOf(this.nat)).toString(16), 2) : '')),
182+
results: this.results,
183+
page: this.page,
184+
version: this.version
185+
}
186+
};
187+
188+
if (this.noInfo) delete json.info;
189+
190+
this.defaultSeed();
191+
this.seedRNG();
192+
193+
if (this.format === 'yaml') {
194+
cb(YAML.stringify(json, 4), "yaml");
195+
} else if (this.format === 'xml') {
196+
cb(js2xmlparser('user', json), "xml");
197+
} else if (this.format === 'prettyjson' || this.format === 'pretty') {
198+
cb(JSON.stringify(json, null, 2), "json");
199+
} else if (this.format === 'csv') {
200+
converter.json2csv(json.results, (err, csv) => {
201+
cb(csv, "csv");
202+
});
203+
} else {
204+
cb(JSON.stringify(json), "json");
205+
}
206+
};
207+
208+
209+
Generator.prototype.seedRNG = function() {
210+
let seed = this.seed;
211+
if (this.seed.length === 18) {
212+
seed = this.seed.substring(0, 16);
213+
}
214+
seed = this.page !== 1 ? seed + String(this.page) : seed;
215+
216+
seed = parseInt(crypto.createHash('md5').update(seed).digest('hex').substring(0, 8), 16);
217+
mersenne.seed(seed);
218+
faker.seed(seed);
219+
};
220+
221+
Generator.prototype.defaultSeed = function() {
222+
this.seed = random(1, 16);
223+
};
224+
225+
Generator.prototype.randomNat = function() {
226+
return this.nats[range(0, this.nats.length-1)];
227+
};
228+
229+
Generator.prototype.validNat = function(nat) {
230+
if (Array.isArray(nat)) {
231+
for (let i = 0; i < nat.length; i++) {
232+
if (this.nats.indexOf(nat[i]) === -1) {
233+
return false;
234+
}
235+
}
236+
} else {
237+
return this.nats.indexOf(nat) !== -1;
238+
}
239+
return true;
240+
};
241+
242+
Generator.prototype.randomName = function(gender, nat) {
243+
gender = gender === undefined ? randomItem(['male', 'female']) : gender;
244+
return [randomItem(datasets[version][nat][gender + '_first']), randomItem(datasets[version][nat]['last'])];
245+
};
246+
247+
Generator.prototype.getNats = function() {
248+
let exclude = ['common', 'LEGO'];
249+
let nats = Object.keys(datasets[version]).filter((nat) => {
250+
return exclude.indexOf(nat) == -1;
251+
});
252+
return nats;
253+
};
254+
255+
Generator.prototype.include = function(field, value) {
256+
if (this.inc.indexOf(field) !== -1) {
257+
current[field] = value;
258+
}
259+
};
260+
261+
Generator.prototype.checkOptions = function(options) {
262+
let keys = Object.keys(options);
263+
for (let i = 0; i < keys.length; i++) {
264+
if (Array.isArray(options[keys[i]])) {
265+
options[keys[i]] = options[keys[i]][options[keys[i]].length-1];
266+
}
267+
}
268+
};
269+
270+
Generator.prototype.genPassword = function() {
271+
if (this.password.length === 0) {
272+
return randomItem(datasets[version].common.passwords);
273+
}
274+
275+
let charsets = {
276+
special: " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
277+
upper: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
278+
lower: "abcdefghijklmnopqrstuvwxyz",
279+
number: "0123456789"
280+
};
281+
282+
// Parse sections
283+
let sections = ["special", "upper", "lower", "number"];
284+
let matches = this.password.split(',').filter(val => sections.indexOf(val) !== -1)
285+
286+
if (matches.length === 0) {
287+
return randomItem(datasets[version].common.passwords);
288+
}
289+
290+
matches = matches.filter((v,i,self) => self.indexOf(v) === i);
291+
292+
// Construct charset to choose from
293+
let charset = "";
294+
matches.forEach(match => {
295+
charset += charsets[match];
296+
});
297+
298+
let length = this.password.split(',').slice(-1)[0];
299+
300+
// Range
301+
let min, max;
302+
if (length.indexOf('-') !== -1) {
303+
let range = length.split('-').map(Number);
304+
min = Math.min(...range);
305+
max = Math.max(...range);
306+
} else {
307+
min = Number(Number(length));
308+
max = min;
309+
}
310+
min = min > 64 || min < 1 || min === undefined || isNaN(min) ? 8 : min;
311+
max = max > 64 || max < 1 || max === undefined || isNaN(max) ? 64 : max;
312+
313+
let passLen = range(min, max);
314+
315+
// Generate password
316+
let password = "";
317+
for (let i = 0; i < passLen; i++) {
318+
password += String(charset[range(0, charset.length-1)]);
319+
}
320+
321+
return password;
322+
};
323+
324+
let random = (mode, length) => {
325+
let result = '';
326+
let chars;
327+
328+
if (mode == 1) {
329+
chars = 'abcdef1234567890';
330+
} else if (mode == 2) {
331+
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
332+
} else if (mode == 3) {
333+
chars = '0123456789';
334+
} else if (mode == 4) {
335+
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
336+
}
337+
for (let i = 0; i < length; i++) {
338+
result += chars[range(0, chars.length-1)];
339+
}
340+
341+
return result;
342+
};
343+
344+
let randomItem = (arr) => {
345+
return arr[range(0, arr.length-1)];
346+
};
347+
348+
let pad = (n, width, z) => {
349+
z = z || '0';
350+
n = n + '';
351+
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
352+
}
353+
354+
let range = (min, max) => {
355+
return min + mersenne.rand(max-min+1);
356+
};
357+
358+
let uppercaseify = (val) => {
359+
if (Array.isArray(val)) {
360+
return val.map((str) => {
361+
return str.toUpperCase();
362+
});
363+
} else {
364+
return val.toUpperCase();
365+
}
366+
}
367+
368+
let include = (inc, field, value) => {
369+
if (inc.indexOf(field) !== -1) {
370+
if (typeof value === 'function') value();
371+
else current[field] = value;
372+
}
373+
};
374+
375+
module.exports = Generator;

api/1.2/data/AU/inject.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module.exports = (inc, contents) => {
2+
var pic = contents.picture;
3+
delete contents.picture;
4+
5+
include(inc, 'phone', '0' + range(0, 9) + '-' + range(0, 9) + random(3, 3) + '-' + random(3, 4));
6+
include(inc, 'cell', '04' + random(3, 2) + '-' + random(3, 3) + '-' + random(3, 3));
7+
include(inc, 'id', {
8+
name: 'TFN',
9+
value: random(3, 9)
10+
});
11+
include(inc, 'picture', pic);
12+
include(inc, 'location', () => {
13+
contents.location.postcode = range(200, 9999); // Override common postcode with AU range
14+
15+
// Override common postcode with AU range
16+
var oldStreet = contents.location.street;
17+
contents.location.street = contents.location.street.replace(/(\d+)/, range(1,9999));
18+
});
19+
};

0 commit comments

Comments
 (0)