UNPKG

2.61 kBJavaScriptView Raw
1'use strict';
2
3/**
4 * Authorization Token
5 * @module auth_token
6 */
7
8var crypto = require('crypto');
9var smart_escape = require('./utils/encoding/smart_escape');
10
11var unsafe = /([ "#%&'/:;<=>?@[\]^`{|}~]+)/g;
12
13function digest(message, key) {
14 return crypto.createHmac("sha256", Buffer.from(key, "hex")).update(message).digest('hex');
15}
16
17/**
18 * Escape url using lowercase hex code
19 * @param {string} url a url string
20 * @return {string} escaped url
21 */
22function escapeToLower(url) {
23 var safeUrl = smart_escape(url, unsafe);
24 return safeUrl.replace(/%../g, function (match) {
25 return match.toLowerCase();
26 });
27}
28
29/**
30 * Auth token options
31 * @typedef {object} authTokenOptions
32 * @property {string} [token_name="__cld_token__"] The name of the token.
33 * @property {string} key The secret key required to sign the token.
34 * @property {string} ip The IP address of the client.
35 * @property {number} start_time=now The start time of the token in seconds from epoch.
36 * @property {string} expiration The expiration time of the token in seconds from epoch.
37 * @property {string} duration The duration of the token (from start_time).
38 * @property {string} acl The ACL for the token.
39 * @property {string} url The URL to authentication in case of a URL token.
40 *
41 */
42
43/**
44 * Generate an authorization token
45 * @param {authTokenOptions} options
46 * @returns {string} the authorization token
47 */
48module.exports = function (options) {
49 var tokenName = options.token_name ? options.token_name : "__cld_token__";
50 var tokenSeparator = "~";
51 if (options.expiration == null) {
52 if (options.duration != null) {
53 var start = options.start_time != null ? options.start_time : Math.round(Date.now() / 1000);
54 options.expiration = start + options.duration;
55 } else {
56 throw new Error("Must provide either expiration or duration");
57 }
58 }
59 var tokenParts = [];
60 if (options.ip != null) {
61 tokenParts.push(`ip=${options.ip}`);
62 }
63 if (options.start_time != null) {
64 tokenParts.push(`st=${options.start_time}`);
65 }
66 tokenParts.push(`exp=${options.expiration}`);
67 if (options.acl != null) {
68 tokenParts.push(`acl=${escapeToLower(options.acl)}`);
69 }
70 var toSign = [].concat(tokenParts);
71 if (options.url != null && options.acl == null) {
72 var url = escapeToLower(options.url);
73 toSign.push(`url=${url}`);
74 }
75 var auth = digest(toSign.join(tokenSeparator), options.key);
76 tokenParts.push(`hmac=${auth}`);
77
78 if (!options.url && !options.acl) {
79 throw 'authToken must contain either an acl or a url property';
80 }
81
82 return `${tokenName}=${tokenParts.join(tokenSeparator)}`;
83};
\No newline at end of file