-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathqranode.js
127 lines (115 loc) · 4.6 KB
/
qranode.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
'use strict'
const { prettifiedName, version } = require('./package.json')
const BASE_URL = 'https://api.quantumnumbers.anu.edu.au'
const DEFAULT_UA = `${prettifiedName}/${version}`
const LIMIT = 1024
const BLOCK_LIMIT = 10
const VALID_TYPES = ['uint8', 'uint16', 'hex8', 'hex16']
/**
* Get some random numbers from https://quantumnumbers.anu.edu.au.
* @param {String} apiKey Your API key. An error will be thrown if not provided.
* @param {String?} userAgent A custom user agent. If undefined, defaults to using the package name and version.
*/
function setup(apiKey, userAgent) {
if (!apiKey) {
throw new Error(`The 'apiKey' argument is required.`)
}
/**
* @async
* @param {object} args
* - `uint8` - returns numbers between 0 and 255.
* - `uint16` - returns numbers between 0 and 65535.
* - `hex8` - returns hexadecimal chunks between `00` and `ff`.
* - `hex16` - returns hexadecimal chunks between `0000` and `ffff`.
* For the hexadecimal types, each block is made up of `args.blockSize` chunks.
*
* @param {string?} [args.dataType] Must be either `uint8`, `uint16`, or `hex16`. Defaults to `uint8`.
* @param {number?} [args.amount] The amount of numbers to get. Max array size is `1024`. Defaults to `1`.
* @param {number?} [args.blockSize] The length of each hex block. Max block size is `10`. Defaults to `1`.
* Only used with the hex types.
* @returns {Promise<{success:boolean,type:string,length:string,data:string[]|number[]}>} A JSON object with the success status, the type requested, the length of the array, and the array of numbers.
* @example
* // The example below is the result of a request for two hex16 numbers with a block size of 4.
await qrng({ dataType: 'hex16', amount: 2, blockSize: 4 })
{
success: true,
type: 'hex16',
length: '2',
data: [ '2f2497d207a39d67', 'dd537fa2b1c4c6b2' ]
}
*/
function wrapper(args) {
return getRandomNumbers({
...args,
apiKey,
userAgent,
})
}
return wrapper
}
async function getRandomNumbers({ dataType = 'uint8', amount = 1, blockSize = 1, apiKey, userAgent }) {
// prepare param object
let reqParams = {}
// set the headers
let HEADERS = {}
HEADERS['x-api-key'] = apiKey
HEADERS['x-user-agent'] = `${userAgent} (with ${DEFAULT_UA})` || DEFAULT_UA
// if theres no API key, don't bother doing anything else
if (!apiKey) {
throw new Error(`The 'apiKey' argument is required.`)
}
if (!dataType || typeof dataType !== 'string') {
throw new Error(`The 'dataType' argument must be one of these: ${VALID_TYPES.join(', ')}`)
}
// shift dataType to lowercase
dataType = dataType.toLowerCase()
// do some quick validation, requesting negative numbers from
// a quantum void would probably end the world
if (!VALID_TYPES.includes(dataType)) {
throw new Error(`The 'dataType' argument must be one of these: ${VALID_TYPES.join(', ')}`)
}
if (typeof amount !== 'number' || isNaN(amount)) {
throw new Error(`The 'amount' argument needs to be a positive integer.`)
}
amount = +amount /// quietly flip all ints positive
if (amount < 1 || amount > LIMIT) {
throw new Error(`The 'amount' argument is outside the range 1-${LIMIT}, inclusive.`)
}
// if the user wants hexadecimal, make sure the blockSize is within bounds
if (dataType.startsWith('hex')) {
if (typeof blockSize !== 'number' || isNaN(blockSize)) {
throw new Error(`The 'blockSize' argument needs to be a positive integer.`)
}
blockSize = +blockSize
if (blockSize < 1 || blockSize > BLOCK_LIMIT) {
throw new Error(`The 'blockSize' argument is outside the range 1-${BLOCK_LIMIT}, inclusive.`)
}
reqParams['size'] = blockSize
}
// params validated, add to object
reqParams['type'] = dataType
reqParams['length'] = amount
// Time to get the data!
try {
const req = await fetch(`${BASE_URL}?${new URLSearchParams(reqParams)}`, {
headers: HEADERS,
})
const response = await req.json()
if (response.success) {
return response
} else {
throw new Error(`failed response from server: ${JSON.stringify(response)}`)
}
} catch (e) {
throw e
}
}
module.exports = setup
/**
* @deprecated
* @param {object} args same as main func
*/
module.exports.getRandomNumbers = (args) => {
console.log('getRandomNumbers is deprecated')
return getRandomNumbers(args)
}