@steedos/auth 2.2.50 → 2.2.51-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -5
- package/lib/apikey.d.ts +0 -9
- package/lib/auth-middleware.d.ts +0 -7
- package/lib/endpoints/jwt.d.ts +0 -1
- package/lib/endpoints/login.d.ts +0 -2
- package/lib/endpoints/logout.d.ts +0 -2
- package/lib/endpoints/validate.d.ts +0 -2
- package/lib/express-middleware.d.ts +0 -1
- package/lib/index.d.ts +0 -8
- package/lib/session.d.ts +0 -18
- package/lib/spaceUserSession.d.ts +0 -4
- package/lib/tokenMap.d.ts +0 -2
- package/lib/userSession.d.ts +0 -3
- package/lib/utils/index.d.ts +0 -12
- package/lib/utils/random.d.ts +0 -2
- package/src/apikey.ts +0 -36
- package/src/auth-middleware.ts +0 -18
- package/src/creator.d.ts +0 -7
- package/src/endpoints/jwt.ts +0 -77
- package/src/endpoints/login.ts +0 -38
- package/src/endpoints/logout.ts +0 -8
- package/src/endpoints/validate.ts +0 -33
- package/src/express-middleware.ts +0 -19
- package/src/index.ts +0 -8
- package/src/session.ts +0 -172
- package/src/spaceUserSession.ts +0 -149
- package/src/tokenMap.ts +0 -54
- package/src/userSession.ts +0 -59
- package/src/utils/index.ts +0 -82
- package/src/utils/random.ts +0 -236
- package/test/init.js +0 -12
- package/test/mocha.opts +0 -7
- package/test/tsconfig.json +0 -11
- package/test/tslint.json +0 -6
- package/test/unit/jwt.test.ts +0 -11
- package/test/unit/session.test.ts +0 -61
- package/test/unit/utils/utils.test..ts +0 -47
- package/test/utils/test-setup.ts +0 -7
- package/tsconfig.json +0 -15
package/src/spaceUserSession.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { getSteedosSchema, addConfig, getConfig, removeConfig } from '@steedos/objectql';
|
|
2
|
-
import { isExpried } from './utils'
|
|
3
|
-
const _ = require('underscore');
|
|
4
|
-
const sessionCacheInMinutes = 10;
|
|
5
|
-
const SPACEUSERCACHENAME = 'space_users_cache';
|
|
6
|
-
|
|
7
|
-
const internalProfiles = ['admin', 'user', 'supplier', 'customer']
|
|
8
|
-
|
|
9
|
-
async function getSpaceUserProfile(userId: string, spaceId: string) {
|
|
10
|
-
let filters = `(space eq '${spaceId}') and (user eq '${userId}')`;
|
|
11
|
-
let spaceUser = await getSteedosSchema().getObject('space_users').find({ filters: filters, fields: ['profile'] });
|
|
12
|
-
if (spaceUser && spaceUser.length > 0) {
|
|
13
|
-
return spaceUser[0].profile
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async function getUserRoles(userId: string, spaceId: string) {
|
|
18
|
-
let roles = ['user'];
|
|
19
|
-
let space = await getSteedosSchema().getObject('spaces').findOne(spaceId, { fields: ['admins'] });
|
|
20
|
-
if (space && space.admins.includes(userId)) {
|
|
21
|
-
roles = ['admin'];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
let profile = await getSpaceUserProfile(userId, spaceId);
|
|
25
|
-
|
|
26
|
-
if (profile) {
|
|
27
|
-
roles = [profile]
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
let filters = `(space eq '${spaceId}') and (users eq '${userId}')`;
|
|
31
|
-
let permission_sets = await getSteedosSchema().getObject('permission_set').directFind({ filters: filters, fields: ['name'] });
|
|
32
|
-
permission_sets.forEach(p => {
|
|
33
|
-
if (!_.include(internalProfiles, p.name)) {
|
|
34
|
-
roles.push(p.name);
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
return roles;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async function getObjectDataByIds(objectName: string, ids: string[], fields?: string[]) {
|
|
41
|
-
if (!ids || ids.length === 0) {
|
|
42
|
-
return []
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let filters = _.map(ids, function (id) {
|
|
46
|
-
if (!id) {
|
|
47
|
-
return ''
|
|
48
|
-
}
|
|
49
|
-
return `(_id eq '${id}')`
|
|
50
|
-
}).join(' or ');
|
|
51
|
-
|
|
52
|
-
if (!filters) {
|
|
53
|
-
return []
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
let query = { filters: filters };
|
|
57
|
-
if (fields && fields.length > 0) {
|
|
58
|
-
query['fields'] = fields;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return await getSteedosSchema().getObject(objectName).directFind(query)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async function getUserPermissionShares(spaceUser) {
|
|
65
|
-
let userFilters = [`(users eq '${spaceUser.user}')`];
|
|
66
|
-
_.each(spaceUser.organizations_parents, (orgId) => {
|
|
67
|
-
userFilters.push(`(organizations eq '${orgId}')`);
|
|
68
|
-
})
|
|
69
|
-
let filters = `((${userFilters.join(' or ')}) and space eq '${spaceUser.space}')`
|
|
70
|
-
return await getSteedosSchema().getObject('permission_shares').find({ filters: filters, fields: ['_id', 'object_name'] });
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function getSpaceSessionFromCache(spaceId, userId) {
|
|
74
|
-
let spaceUserSession = getConfig(SPACEUSERCACHENAME, `${spaceId}-${userId}`)
|
|
75
|
-
if (!spaceUserSession) {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
if (isExpried(spaceUserSession.expiredAt)) {
|
|
79
|
-
removeConfig(SPACEUSERCACHENAME, spaceUserSession);
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
return spaceUserSession;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function addSpaceSessionToCache(spaceId, userId, spaceUserSession) {
|
|
86
|
-
spaceUserSession._id = `${spaceId}-${userId}`
|
|
87
|
-
addConfig(SPACEUSERCACHENAME, spaceUserSession);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
export async function getSpaceUserSession(spaceId, userId) {
|
|
92
|
-
let spaceSession: any = getSpaceSessionFromCache(spaceId, userId);
|
|
93
|
-
if (!spaceSession) {
|
|
94
|
-
let expiredAt = new Date().getTime() + sessionCacheInMinutes * 60 * 1000;
|
|
95
|
-
let su = null;
|
|
96
|
-
let suFields = ['_id', 'space', 'company_id', 'company_ids', 'organization', 'organizations', 'organizations_parents', 'user'];
|
|
97
|
-
|
|
98
|
-
// 如果spaceid和user不匹配,则取用户的第一个工作区
|
|
99
|
-
let spaceUsers = await getSteedosSchema().getObject('space_users').directFind({ filters: `(user eq '${userId}') and (user_accepted eq true)`, fields: suFields });
|
|
100
|
-
const findSpaceUser = _.find(spaceUsers, (spaceUser)=>{ return spaceUser.space === spaceId })
|
|
101
|
-
if(findSpaceUser){
|
|
102
|
-
su = findSpaceUser;
|
|
103
|
-
}else{
|
|
104
|
-
su = spaceUsers[0];
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (su) {
|
|
108
|
-
let userSpaceId = su.space;
|
|
109
|
-
let userSpaceIds = _.pluck(spaceUsers, 'space');
|
|
110
|
-
let roles = await getUserRoles(userId, userSpaceId);
|
|
111
|
-
let profile = await getSpaceUserProfile(userId, userSpaceId);
|
|
112
|
-
spaceSession = { roles: roles, profile: profile,expiredAt: expiredAt };
|
|
113
|
-
spaceSession.spaceId = userSpaceId;
|
|
114
|
-
spaceSession.spaces = await getObjectDataByIds('spaces', userSpaceIds, ['name', 'admins']);
|
|
115
|
-
spaceSession.space = _.find(spaceSession.spaces, (record)=>{ return record._id === userSpaceId });
|
|
116
|
-
|
|
117
|
-
spaceSession.companies = await getObjectDataByIds('company', su.company_ids, ['name', 'organization']);
|
|
118
|
-
spaceSession.company = _.find(spaceSession.companies, (record)=>{ return record._id === su.company_id });
|
|
119
|
-
|
|
120
|
-
spaceSession.organizations = await getObjectDataByIds('organizations', su.organizations, ['name', 'fullname', 'company_id']);
|
|
121
|
-
spaceSession.organization = _.find(spaceSession.organizations, (record)=>{ return record._id === su.organization });
|
|
122
|
-
|
|
123
|
-
if (spaceSession.space && spaceSession.space.admins) {
|
|
124
|
-
spaceSession.is_space_admin = spaceSession.space.admins.indexOf(userId) > -1;
|
|
125
|
-
}
|
|
126
|
-
if (spaceSession.company) {
|
|
127
|
-
spaceSession.company_id = spaceSession.company._id;
|
|
128
|
-
}
|
|
129
|
-
if (spaceSession.companies) {
|
|
130
|
-
spaceSession.company_ids = spaceSession.companies.map(function (company: any) { return company._id });
|
|
131
|
-
}
|
|
132
|
-
spaceSession.permission_shares = await getUserPermissionShares(su);
|
|
133
|
-
addSpaceSessionToCache(spaceId, userId, spaceSession);
|
|
134
|
-
return spaceSession;
|
|
135
|
-
} else {
|
|
136
|
-
spaceSession = { roles: ['guest'], expiredAt: expiredAt };
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return spaceSession;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export async function updateSpaceUserSessionRolesCache(spaceId, userId) {
|
|
143
|
-
let spaceSession: any = getSpaceSessionFromCache(spaceId, userId);
|
|
144
|
-
if (spaceSession) {
|
|
145
|
-
spaceSession.roles = await getUserRoles(userId, spaceId);
|
|
146
|
-
return true;
|
|
147
|
-
}
|
|
148
|
-
return false;
|
|
149
|
-
}
|
package/src/tokenMap.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import crypto = require('crypto');
|
|
2
|
-
import {
|
|
3
|
-
getSteedosSchema,
|
|
4
|
-
addConfig,
|
|
5
|
-
getConfig,
|
|
6
|
-
removeManyConfigs,
|
|
7
|
-
} from "@steedos/objectql";
|
|
8
|
-
const TOKENMAPCACHENAME = "token_map_cache";
|
|
9
|
-
|
|
10
|
-
function getTokenMapCache(token) {
|
|
11
|
-
return getConfig(TOKENMAPCACHENAME, token);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function setTokenMapCache(token, tokenMap) {
|
|
15
|
-
tokenMap._id = token;
|
|
16
|
-
addConfig(TOKENMAPCACHENAME, tokenMap);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function _hashLoginToken(token: string) {
|
|
20
|
-
const hash = crypto.createHash("sha256");
|
|
21
|
-
hash.update(token);
|
|
22
|
-
return hash.digest("base64");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async function getUser(token: string) {
|
|
26
|
-
let hashedToken = _hashLoginToken(token).replace(/\//g, "%2F");
|
|
27
|
-
let filters = `(services/resume/loginTokens/hashedToken eq '${hashedToken}')`;
|
|
28
|
-
let users = await getSteedosSchema()
|
|
29
|
-
.getObject("users")
|
|
30
|
-
.find({ filters: filters, fields: ["_id"] });
|
|
31
|
-
return users[0];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export async function getUserIdByToken(token, clientInfos = {}) {
|
|
35
|
-
let tokenMap = getTokenMapCache(token);
|
|
36
|
-
if (!tokenMap) {
|
|
37
|
-
let user = await getUser(token);
|
|
38
|
-
if (user) {
|
|
39
|
-
let userId = user._id;
|
|
40
|
-
setTokenMapCache(
|
|
41
|
-
token,
|
|
42
|
-
Object.assign({}, clientInfos, { userId: userId })
|
|
43
|
-
);
|
|
44
|
-
return userId;
|
|
45
|
-
} else {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return tokenMap.userId;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function removeUserTokens(userId, is_phone) {
|
|
53
|
-
removeManyConfigs(TOKENMAPCACHENAME, { userId: userId, is_phone });
|
|
54
|
-
}
|
package/src/userSession.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { getSteedosSchema, addConfig, getConfig, removeConfig } from '@steedos/objectql';
|
|
2
|
-
import { isExpried } from './utils'
|
|
3
|
-
const sessionCacheInMinutes = 10;
|
|
4
|
-
const USERCACHENAME = 'users_cache';
|
|
5
|
-
|
|
6
|
-
export function getSessionFromCache(userId) {
|
|
7
|
-
let userSession = getConfig(USERCACHENAME, userId)
|
|
8
|
-
if (!userSession) {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
if (isExpried(userSession.expiredAt)) {
|
|
12
|
-
removeConfig(USERCACHENAME, userSession);
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
return userSession;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function addSessionToCache(userId, userSession) {
|
|
19
|
-
userSession._id = userId
|
|
20
|
-
addConfig(USERCACHENAME, userSession);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async function getUser(userId) {
|
|
24
|
-
let user = await getSteedosSchema().getObject('users').findOne(userId, { fields: ['name', 'username', 'mobile', 'email', 'utcOffset', 'steedos_id', 'locale'] });
|
|
25
|
-
return user;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export async function getUserSession(userId) {
|
|
29
|
-
let expiredAt = new Date().getTime() + sessionCacheInMinutes * 60 * 1000;
|
|
30
|
-
let session = getSessionFromCache(userId);
|
|
31
|
-
if (!session) {
|
|
32
|
-
let user = await getUser(userId);
|
|
33
|
-
if (user) {
|
|
34
|
-
session = {};
|
|
35
|
-
session.userId = user._id;
|
|
36
|
-
session.name = user.name;
|
|
37
|
-
session.username = user.username;
|
|
38
|
-
session.mobile = user.mobile;
|
|
39
|
-
session.email = user.email;
|
|
40
|
-
session.utcOffset = user.utcOffset;
|
|
41
|
-
session.steedos_id = user.steedos_id;
|
|
42
|
-
session.locale = user.locale;
|
|
43
|
-
if(user.locale == "en-us"){
|
|
44
|
-
session.language = "en"
|
|
45
|
-
}else if(user.locale == "zh-cn"){
|
|
46
|
-
session.language = "zh-CN"
|
|
47
|
-
}else{
|
|
48
|
-
session.language = user.locale
|
|
49
|
-
}
|
|
50
|
-
session.expiredAt = expiredAt;
|
|
51
|
-
addSessionToCache(userId, session);
|
|
52
|
-
return session;
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
return
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return session
|
|
59
|
-
}
|
package/src/utils/index.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import crypto = require('crypto');
|
|
2
|
-
import { default as Random } from './random';
|
|
3
|
-
import { getSteedosSchema } from '@steedos/objectql';
|
|
4
|
-
const Cookies = require('cookies');
|
|
5
|
-
|
|
6
|
-
export const hashLoginToken = function (loginToken) {
|
|
7
|
-
const hash = crypto.createHash('sha256');
|
|
8
|
-
hash.update(loginToken);
|
|
9
|
-
return hash.digest('base64');
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const generateStampedLoginToken = function () {
|
|
13
|
-
return {
|
|
14
|
-
token: Random.secret(),
|
|
15
|
-
when: new Date
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const hashStampedToken = function (stampedToken) {
|
|
20
|
-
const hashedStampedToken = Object.keys(stampedToken).reduce(
|
|
21
|
-
(prev, key) => key === 'token' ?
|
|
22
|
-
prev :
|
|
23
|
-
{ ...prev, [key]: stampedToken[key] },
|
|
24
|
-
{},
|
|
25
|
-
)
|
|
26
|
-
return {
|
|
27
|
-
...hashedStampedToken,
|
|
28
|
-
hashedToken: hashLoginToken(stampedToken.token)
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const insertHashedLoginToken = async function (userId, hashedToken) {
|
|
33
|
-
let userObject = getSteedosSchema().getObject('users')
|
|
34
|
-
let user = await userObject.findOne(userId, { fields: ['services'] })
|
|
35
|
-
if(!user['services']){
|
|
36
|
-
user['services'] = {}
|
|
37
|
-
}
|
|
38
|
-
if(!user['services']['resume']){
|
|
39
|
-
user['services']['resume'] = {loginTokens: []}
|
|
40
|
-
}
|
|
41
|
-
user['services']['resume']['loginTokens'].push(hashedToken)
|
|
42
|
-
let data = { services: user['services'] }
|
|
43
|
-
return await userObject.update(userId, data);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
export const setAuthCookies = function (req, res, userId, authToken, spaceId?) {
|
|
49
|
-
let cookies = new Cookies(req, res);
|
|
50
|
-
let options = {
|
|
51
|
-
maxAge: 90 * 60 * 60 * 24 * 1000,
|
|
52
|
-
httpOnly: true,
|
|
53
|
-
overwrite: true
|
|
54
|
-
}
|
|
55
|
-
cookies.set("X-User-Id", userId, options);
|
|
56
|
-
cookies.set("X-Auth-Token", authToken, options);
|
|
57
|
-
if (spaceId) {
|
|
58
|
-
cookies.set("X-Space-Id", spaceId, options);
|
|
59
|
-
cookies.set("X-Space-Token", spaceId + ',' + authToken, options);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
export const clearAuthCookies = function (req, res) {
|
|
67
|
-
let cookies = new Cookies(req, res);
|
|
68
|
-
let options = {
|
|
69
|
-
maxAge: 0,
|
|
70
|
-
httpOnly: true,
|
|
71
|
-
overwrite: true
|
|
72
|
-
}
|
|
73
|
-
cookies.set("X-User-Id", null, options);
|
|
74
|
-
cookies.set("X-Auth-Token", null, options);
|
|
75
|
-
cookies.set("X-Access-Token", null, options);
|
|
76
|
-
cookies.set("X-Space-Token", null, options);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function isExpried(expiredAt: number) {
|
|
81
|
-
return expiredAt <= new Date().getTime();
|
|
82
|
-
}
|
package/src/utils/random.ts
DELETED
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
// We use cryptographically strong PRNGs (crypto.getRandomBytes() on the server,
|
|
2
|
-
// window.crypto.getRandomValues() in the browser) when available. If these
|
|
3
|
-
// PRNGs fail, we fall back to the Alea PRNG, which is not cryptographically
|
|
4
|
-
// strong, and we seed it with various sources such as the date, Math.random,
|
|
5
|
-
// and window size on the client. When using crypto.getRandomValues(), our
|
|
6
|
-
// primitive is hexString(), from which we construct fraction(). When using
|
|
7
|
-
// window.crypto.getRandomValues() or alea, the primitive is fraction and we use
|
|
8
|
-
// that to construct hex string.
|
|
9
|
-
|
|
10
|
-
var nodeCrypto = require('crypto');
|
|
11
|
-
|
|
12
|
-
// see http://baagoe.org/en/wiki/Better_random_numbers_for_javascript
|
|
13
|
-
// for a full discussion and Alea implementation.
|
|
14
|
-
var Alea = function () {
|
|
15
|
-
function Mash() {
|
|
16
|
-
var n = 0xefc8249d;
|
|
17
|
-
|
|
18
|
-
var mash = function(data) {
|
|
19
|
-
data = data.toString();
|
|
20
|
-
for (var i = 0; i < data.length; i++) {
|
|
21
|
-
n += data.charCodeAt(i);
|
|
22
|
-
var h = 0.02519603282416938 * n;
|
|
23
|
-
n = h >>> 0;
|
|
24
|
-
h -= n;
|
|
25
|
-
h *= n;
|
|
26
|
-
n = h >>> 0;
|
|
27
|
-
h -= n;
|
|
28
|
-
n += h * 0x100000000; // 2^32
|
|
29
|
-
}
|
|
30
|
-
return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
mash['version'] = 'Mash 0.9';
|
|
34
|
-
return mash;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return (function (args) {
|
|
38
|
-
var s0 = 0;
|
|
39
|
-
var s1 = 0;
|
|
40
|
-
var s2 = 0;
|
|
41
|
-
var c = 1;
|
|
42
|
-
|
|
43
|
-
if (args.length == 0) {
|
|
44
|
-
args = [+new Date];
|
|
45
|
-
}
|
|
46
|
-
var mash = Mash();
|
|
47
|
-
s0 = mash(' ');
|
|
48
|
-
s1 = mash(' ');
|
|
49
|
-
s2 = mash(' ');
|
|
50
|
-
|
|
51
|
-
for (var i = 0; i < args.length; i++) {
|
|
52
|
-
s0 -= mash(args[i]);
|
|
53
|
-
if (s0 < 0) {
|
|
54
|
-
s0 += 1;
|
|
55
|
-
}
|
|
56
|
-
s1 -= mash(args[i]);
|
|
57
|
-
if (s1 < 0) {
|
|
58
|
-
s1 += 1;
|
|
59
|
-
}
|
|
60
|
-
s2 -= mash(args[i]);
|
|
61
|
-
if (s2 < 0) {
|
|
62
|
-
s2 += 1;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
mash = null;
|
|
66
|
-
|
|
67
|
-
var random = function() {
|
|
68
|
-
var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
|
|
69
|
-
s0 = s1;
|
|
70
|
-
s1 = s2;
|
|
71
|
-
return s2 = t - (c = t | 0);
|
|
72
|
-
};
|
|
73
|
-
random['uint32'] = function() {
|
|
74
|
-
return random() * 0x100000000; // 2^32
|
|
75
|
-
};
|
|
76
|
-
random['fract53'] = function() {
|
|
77
|
-
return random() +
|
|
78
|
-
(random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
|
|
79
|
-
};
|
|
80
|
-
random['version'] = 'Alea 0.9';
|
|
81
|
-
random['args'] = args;
|
|
82
|
-
return random;
|
|
83
|
-
|
|
84
|
-
} (Array.prototype.slice.call(arguments)));
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
var UNMISTAKABLE_CHARS = "23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz";
|
|
88
|
-
var BASE64_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +
|
|
89
|
-
"0123456789-_";
|
|
90
|
-
|
|
91
|
-
// `type` is one of `RandomGenerator.Type` as defined below.
|
|
92
|
-
//
|
|
93
|
-
// options:
|
|
94
|
-
// - seeds: (required, only for RandomGenerator.Type.ALEA) an array
|
|
95
|
-
// whose items will be `toString`ed and used as the seed to the Alea
|
|
96
|
-
// algorithm
|
|
97
|
-
var RandomGenerator = function (type, options?) {
|
|
98
|
-
var self = this;
|
|
99
|
-
self.type = type;
|
|
100
|
-
|
|
101
|
-
if (!RandomGenerator['Type'][type]) {
|
|
102
|
-
throw new Error("Unknown random generator type: " + type);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (type === RandomGenerator['Type'].ALEA) {
|
|
106
|
-
if (!options.seeds) {
|
|
107
|
-
throw new Error("No seeds were provided for Alea PRNG");
|
|
108
|
-
}
|
|
109
|
-
self.alea = Alea.apply(null, options.seeds);
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
// Types of PRNGs supported by the `RandomGenerator` class
|
|
114
|
-
RandomGenerator['Type'] = {
|
|
115
|
-
// Use Node's built-in `crypto.getRandomBytes` (cryptographically
|
|
116
|
-
// secure but not seedable, runs only on the server). Reverts to
|
|
117
|
-
// `crypto.getPseudoRandomBytes` in the extremely uncommon case that
|
|
118
|
-
// there isn't enough entropy yet
|
|
119
|
-
NODE_CRYPTO: "NODE_CRYPTO",
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// Use the *fast*, seedaable and not cryptographically secure
|
|
123
|
-
// Alea algorithm
|
|
124
|
-
ALEA: "ALEA",
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* @name Random.fraction
|
|
129
|
-
* @summary Return a number between 0 and 1, like `Math.random`.
|
|
130
|
-
* @locus Anywhere
|
|
131
|
-
*/
|
|
132
|
-
RandomGenerator.prototype.fraction = function () {
|
|
133
|
-
var self = this;
|
|
134
|
-
if (self.type === RandomGenerator['Type'].ALEA) {
|
|
135
|
-
return self.alea();
|
|
136
|
-
} else if (self.type === RandomGenerator['Type'].NODE_CRYPTO) {
|
|
137
|
-
var numerator = parseInt(self.hexString(8), 16);
|
|
138
|
-
return numerator * 2.3283064365386963e-10; // 2^-32
|
|
139
|
-
} else {
|
|
140
|
-
throw new Error('Unknown random generator type: ' + self.type);
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* @name Random.hexString
|
|
146
|
-
* @summary Return a random string of `n` hexadecimal digits.
|
|
147
|
-
* @locus Anywhere
|
|
148
|
-
* @param {Number} n Length of the string
|
|
149
|
-
*/
|
|
150
|
-
RandomGenerator.prototype.hexString = function (digits) {
|
|
151
|
-
var self = this;
|
|
152
|
-
if (self.type === RandomGenerator['Type'].NODE_CRYPTO) {
|
|
153
|
-
var numBytes = Math.ceil(digits / 2);
|
|
154
|
-
var bytes;
|
|
155
|
-
// Try to get cryptographically strong randomness. Fall back to
|
|
156
|
-
// non-cryptographically strong if not available.
|
|
157
|
-
try {
|
|
158
|
-
bytes = nodeCrypto.randomBytes(numBytes);
|
|
159
|
-
} catch (e) {
|
|
160
|
-
// XXX should re-throw any error except insufficient entropy
|
|
161
|
-
bytes = nodeCrypto.pseudoRandomBytes(numBytes);
|
|
162
|
-
}
|
|
163
|
-
var result = bytes.toString("hex");
|
|
164
|
-
// If the number of digits is odd, we'll have generated an extra 4 bits
|
|
165
|
-
// of randomness, so we need to trim the last digit.
|
|
166
|
-
return result.substring(0, digits);
|
|
167
|
-
} else {
|
|
168
|
-
return this._randomString(digits, "0123456789abcdef");
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
RandomGenerator.prototype._randomString = function (charsCount,
|
|
173
|
-
alphabet) {
|
|
174
|
-
var self = this;
|
|
175
|
-
var digits = [];
|
|
176
|
-
for (var i = 0; i < charsCount; i++) {
|
|
177
|
-
digits[i] = self.choice(alphabet);
|
|
178
|
-
}
|
|
179
|
-
return digits.join("");
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* @name Random.id
|
|
184
|
-
* @summary Return a unique identifier, such as `"Jjwjg6gouWLXhMGKW"`, that is
|
|
185
|
-
* likely to be unique in the whole world.
|
|
186
|
-
* @locus Anywhere
|
|
187
|
-
* @param {Number} [n] Optional length of the identifier in characters
|
|
188
|
-
* (defaults to 17)
|
|
189
|
-
*/
|
|
190
|
-
RandomGenerator.prototype.id = function (charsCount) {
|
|
191
|
-
var self = this;
|
|
192
|
-
// 17 characters is around 96 bits of entropy, which is the amount of
|
|
193
|
-
// state in the Alea PRNG.
|
|
194
|
-
if (charsCount === undefined)
|
|
195
|
-
charsCount = 17;
|
|
196
|
-
|
|
197
|
-
return self._randomString(charsCount, UNMISTAKABLE_CHARS);
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* @name Random.secret
|
|
202
|
-
* @summary Return a random string of printable characters with 6 bits of
|
|
203
|
-
* entropy per character. Use `Random.secret` for security-critical secrets
|
|
204
|
-
* that are intended for machine, rather than human, consumption.
|
|
205
|
-
* @locus Anywhere
|
|
206
|
-
* @param {Number} [n] Optional length of the secret string (defaults to 43
|
|
207
|
-
* characters, or 256 bits of entropy)
|
|
208
|
-
*/
|
|
209
|
-
RandomGenerator.prototype.secret = function (charsCount) {
|
|
210
|
-
var self = this;
|
|
211
|
-
// Default to 256 bits of entropy, or 43 characters at 6 bits per
|
|
212
|
-
// character.
|
|
213
|
-
if (charsCount === undefined)
|
|
214
|
-
charsCount = 43;
|
|
215
|
-
return self._randomString(charsCount, BASE64_CHARS);
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* @name Random.choice
|
|
220
|
-
* @summary Return a random element of the given array or string.
|
|
221
|
-
* @locus Anywhere
|
|
222
|
-
* @param {Array|String} arrayOrString Array or string to choose from
|
|
223
|
-
*/
|
|
224
|
-
RandomGenerator.prototype.choice = function (arrayOrString) {
|
|
225
|
-
var index = Math.floor(this.fraction() * arrayOrString.length);
|
|
226
|
-
if (typeof arrayOrString === "string")
|
|
227
|
-
return arrayOrString.substr(index, 1);
|
|
228
|
-
else
|
|
229
|
-
return arrayOrString[index];
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
let Random = new RandomGenerator(RandomGenerator['Type'].NODE_CRYPTO);
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
export default Random
|
package/test/init.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2018, salesforce.com, inc.
|
|
3
|
-
* All rights reserved.
|
|
4
|
-
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
-
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
-
*/
|
|
7
|
-
const path = require('path');
|
|
8
|
-
process.env.TS_NODE_PROJECT = path.resolve('test/tsconfig.json');
|
|
9
|
-
// process.env.DRIVER_SQLSERVER_URL = "mssql://sa:hotoainc.@192.168.0.190/driver-test";
|
|
10
|
-
// process.env.DRIVER_SQLSERVER_URL = "mssql://sa:hotoainc.@192.168.0.78/driver-test";
|
|
11
|
-
// process.env.DRIVER_SQLSERVER_TDS = "7_2";//7_2为2005,7_4为2012+,默认为7_4
|
|
12
|
-
|
package/test/mocha.opts
DELETED
package/test/tsconfig.json
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../../node_modules/@salesforce/dev-config/tsconfig",
|
|
3
|
-
"include": ["unit/**/*.ts", "../node_modules/@types/**/*.d.ts"],
|
|
4
|
-
"compilerOptions": {
|
|
5
|
-
"noEmit": true,
|
|
6
|
-
"strict": false,
|
|
7
|
-
"noUnusedLocals": true,
|
|
8
|
-
"emitDecoratorMetadata": true,
|
|
9
|
-
"experimentalDecorators": true
|
|
10
|
-
}
|
|
11
|
-
}
|
package/test/tslint.json
DELETED
package/test/unit/jwt.test.ts
DELETED