UNPKG

5.8 kBJavaScriptView Raw
1var STORE = require('store-ttl');
2var _ = require('lodash');
3var util = require('./util');
4var async = require('async');
5function randomToken(len) {
6 return Math.random().toString(len || 26).slice(2);
7}
8
9function Token(config) {
10 if (!_.isObject(config)) {
11 config = {};
12 }
13 config.storeConfig = config.storeConfig || {};
14 config.count = config.count || 5;
15 this.config = config;
16 this.store = new STORE(config.storeConfig);
17 this.config.webTokenVarName = this.config.webTokenVarName || 'encrypt_api_tokenStr'
18}
19
20Token.prototype.issue = function(ttl, count, token, cb) {
21 var store = this.store;
22 if (_.isFunction(ttl)) {
23 return ttl('issue api must be set ttl.');
24 }
25 if(_.isFunction(count)) {
26 cb = count;
27 token = randomToken();
28 count = this.config.count;;
29 }
30 if (_.isString(count) && _.isFunction(token)) {
31 cb = token;
32 token = count;
33 count = this.config.count;
34 }
35 if (_.isNumber(count) && _.isFunction(token)) {
36 cb = token;
37 token = randomToken();
38 }
39 if (!_.isFunction(cb)) {
40 throw 'issue api is async function, you must have callback function.'
41 }
42 store.set(token, count, ttl, function(err, data) {
43 if (!err && data) {
44 cb(null, token);
45 } else {
46 cb(err || 'issue token error : ' + data);
47 }
48 });
49}
50
51Token.prototype.verify = function(token, cb) {
52 var store = this.store;
53 store.get(token, function(err, data) {
54 if (!err && data) {
55 cb(null, data.data);
56 } else {
57 cb(err || 'token : ' + token + ' haved expire.')
58 }
59 });
60}
61
62Token.prototype.remove = function(token, cb) {
63 var store = this.store;
64 store.remove(token, function(err, data) {
65 cb(err, data);
66 });
67}
68
69Token.prototype.decline = function(token, cb) {
70 var store = this.store;
71 store.get(token, function(err, data) {
72 if (!err && data) {
73 store.update(token, --data.data, function(err, data) {
74 cb(err, (data && data.data));
75 });
76 } else {
77 cb(err || 'not exists or expired token : ' + token + '.')
78 }
79 })
80}
81
82Token.prototype.webInject = function(html, token, callback) {
83 if (!_.isString(html)) {
84 return callback('html must be string', html);
85 }
86 var webTokenVarName = this.config.webTokenVarName;
87 var webInject = this.config.webInject || function(html, token, callback) {
88 var bodyEndStr = '</body>';
89 var bodyStartStr = '<body';
90 var tokenId = '_' + util.generateSalt(Math.ceil(Math.random() * 10));
91 var bodyStarIndex = html.indexOf(bodyStartStr);
92 var bodyEndIndex = html.indexOf(bodyEndStr);
93 var htmlTagLastIndexs = util.matchHtmlTags(html.substring(bodyStarIndex, bodyEndIndex + 1));
94 if (!htmlTagLastIndexs.length) {
95 htmlTagLastIndexs[0] = bodyEndIndex - bodyStarIndex;
96 }
97 var htmlTagLen = htmlTagLastIndexs.length;
98 var tokenLen = token.length;
99 var times = Math.floor(htmlTagLen / tokenLen);
100 var randomIndex = 0;
101 var addLen = 0;
102 var scriptStr = 'var r="";function g(id){return document.getElementById(id).innerHTML}';
103 for (var i = 0; i < tokenLen; i++) {
104 var htmlTag = util.makeHtmlTag(tokenId + i, token[i]);
105 randomIndex += Math.floor(Math.random() * times);
106 if (!htmlTagLastIndexs[randomIndex]) {
107 randomIndex = htmlTagLen - 1;
108 }
109 var curIndex = bodyStarIndex + htmlTagLastIndexs[randomIndex] + addLen;
110 var prevHtml = html.substring(0, curIndex);
111 var nextHtml = html.substr(curIndex);
112 scriptStr += 'r += g("' + (tokenId + i) + '");';
113 if (i === tokenLen - 1) {
114 scriptStr += 'w.' + webTokenVarName + '=r;';
115 html = prevHtml.concat(htmlTag, '<script>(function(w){' + scriptStr + '})(window)</script>', nextHtml);
116 } else {
117 html = prevHtml.concat(htmlTag, nextHtml);
118 }
119 addLen += htmlTag.length;
120 }
121 callback(null, html);
122 };
123 webInject.call(this, html, token, callback);
124}
125
126Token.prototype.pass = function(token, cb) {
127 var that = this;
128 this.verify(token, function(err, data) {
129 if (err) {
130 return cb(err, {
131 code: -1,
132 msg: err,
133 passed: false
134 });
135 }
136 if (data) {
137 that.decline(token, function(err, count) {
138 if (!err) {
139 return cb(null, {
140 code: 0,
141 msg: 'ok',
142 passed: true,
143 count: count
144 })
145 }
146 cb(err, {
147 code: -2,
148 msg: 'decline token times error : ' + err,
149 passed: false
150 })
151 });
152 } else {
153 cb(null, {
154 code: 1,
155 msg: 'access token times haved used out.',
156 passed: false,
157 count: 0
158 })
159 }
160 })
161}
162
163
164Token.prototype.limit = function(apiName, ttl, callCount, cb) {
165 var _this = this;
166 if (!_.isString(apiName)) {
167 cb = arguments[arguments.length-1];
168 return cb('the first param must be string');
169 }
170 async.waterfall([
171 function(cb) {
172 var code = 0;
173 _this.verify(apiName, function(err, count) {
174 if (err) {
175 code = 1;
176 }
177 if (count === 0) {
178 code = 2;
179 }
180 cb(null, code);
181 })
182 },
183 function(code, cb) {
184 switch (code) {
185 case 0:
186 _this.decline(apiName, function(err, count) {
187 cb(err);
188 })
189 break;
190 case 1:
191 _this.issue(ttl, callCount, apiName, function(err, data) {
192 cb(err);
193 })
194 break;
195 case 2:
196 cb(apiName + 'limited number of calls.');
197 break;
198 default:
199 cb(apiName + 'called error.');
200 }
201 }
202 ], function(err) {
203 cb(err);
204 })
205}
206
207module.exports = Token;
\No newline at end of file