skapi-js 0.0.3 → 0.0.41
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/README.md +1 -1
- package/deploy.py +6 -0
- package/dist/skapi.js +1 -1
- package/dist/skapi.js.map +1 -1
- package/dist/skapi.module.js +3 -0
- package/dist/skapi.module.js.LICENSE.txt +21 -0
- package/dist/skapi.module.js.map +1 -0
- package/package.json +5 -4
- package/src/decorators.ts +2 -1
- package/src/skapi.ts +88 -157
- package/src/utils.ts +31 -27
- package/tsconfig.json +2 -2
- package/webpack.config.js +16 -12
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skapi-js",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "skapi javascript library",
|
|
5
|
-
"main": "./dist/skapi.js",
|
|
3
|
+
"version": "0.0.41",
|
|
4
|
+
"description": "skapi serverless cloud javascript library",
|
|
5
|
+
"main": "./dist/skapi.module.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "npx tsc ; npx webpack --config webpack.config.js ; npx typedoc"
|
|
8
8
|
},
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"backend",
|
|
28
28
|
"serverless",
|
|
29
29
|
"skapi",
|
|
30
|
-
"api"
|
|
30
|
+
"api",
|
|
31
|
+
"cloud"
|
|
31
32
|
],
|
|
32
33
|
"dependencies": {
|
|
33
34
|
"amazon-cognito-identity-js": "^5.2.12"
|
package/src/decorators.ts
CHANGED
|
@@ -29,7 +29,8 @@ function formResponse() {
|
|
|
29
29
|
|
|
30
30
|
// form element action
|
|
31
31
|
let href = new URL(form.action);
|
|
32
|
-
let response_key = sha256(form.action);
|
|
32
|
+
// let response_key = sha256(form.action);
|
|
33
|
+
let response_key = form.action;
|
|
33
34
|
let timestamp = Date.now().toString();
|
|
34
35
|
|
|
35
36
|
window.sessionStorage.setItem(response_key, JSON.stringify({ [timestamp]: response }));
|
package/src/skapi.ts
CHANGED
|
@@ -110,7 +110,21 @@ export default class Skapi {
|
|
|
110
110
|
// public
|
|
111
111
|
|
|
112
112
|
/** Current logged in user object. null if not logged. */
|
|
113
|
-
|
|
113
|
+
__user: User | null = null;
|
|
114
|
+
|
|
115
|
+
get user() {
|
|
116
|
+
if (this.__user && Object.keys(this.__user).length) {
|
|
117
|
+
return JSON.parse(JSON.stringify(this.__user));
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
set user(value) {
|
|
125
|
+
// setting user is bypassed
|
|
126
|
+
}
|
|
127
|
+
|
|
114
128
|
/** Connected service object. null if connection failed. */
|
|
115
129
|
connection: Connection | null = null;
|
|
116
130
|
host: string = 'skapi';
|
|
@@ -411,7 +425,7 @@ export default class Skapi {
|
|
|
411
425
|
user.access_group = Number(this.session.idToken.payload.access_group);
|
|
412
426
|
user.user_id = user.sub;
|
|
413
427
|
delete user.sub;
|
|
414
|
-
this.
|
|
428
|
+
this.__user = user;
|
|
415
429
|
res(user);
|
|
416
430
|
}
|
|
417
431
|
});
|
|
@@ -577,6 +591,10 @@ export default class Skapi {
|
|
|
577
591
|
return await this.request(p.url, option || null, { method: 'get', auth: p.url.includes('/auth/'), contentType: null, responseType: 'blob' });
|
|
578
592
|
}
|
|
579
593
|
|
|
594
|
+
async mock(data, options) {
|
|
595
|
+
return this.request('test-api', data, options);
|
|
596
|
+
}
|
|
597
|
+
|
|
580
598
|
/**
|
|
581
599
|
* Sends post request to your custom server using Skapi's secure API layer.</br>
|
|
582
600
|
* You must set your secret API key from the Skapi's admin page.</br>
|
|
@@ -735,7 +753,7 @@ export default class Skapi {
|
|
|
735
753
|
* Retrives respond data from form request.
|
|
736
754
|
*
|
|
737
755
|
* ```
|
|
738
|
-
* let respond = skapi.
|
|
756
|
+
* let respond = skapi.getFormResponse();
|
|
739
757
|
* ```
|
|
740
758
|
* @category Connection
|
|
741
759
|
*/
|
|
@@ -835,6 +853,7 @@ export default class Skapi {
|
|
|
835
853
|
case 'signup':
|
|
836
854
|
case 'confirm-signup':
|
|
837
855
|
case 'recover-account':
|
|
856
|
+
case 'test-api':
|
|
838
857
|
case 'service':
|
|
839
858
|
return {
|
|
840
859
|
public: admin.admin_public,
|
|
@@ -1008,11 +1027,11 @@ export default class Skapi {
|
|
|
1008
1027
|
}
|
|
1009
1028
|
|
|
1010
1029
|
let requestKey = this.load_startKey_keys({
|
|
1011
|
-
params:
|
|
1030
|
+
params: data,
|
|
1012
1031
|
url: isExternalUrl || url,
|
|
1013
1032
|
refresh: isForm ? true : refresh // should not use startKey when post is a form
|
|
1014
1033
|
}); // returns requrestKey | cached data
|
|
1015
|
-
|
|
1034
|
+
|
|
1016
1035
|
if (requestKey && typeof requestKey === 'object') {
|
|
1017
1036
|
return requestKey;
|
|
1018
1037
|
}
|
|
@@ -1093,7 +1112,7 @@ export default class Skapi {
|
|
|
1093
1112
|
}): string | FetchResponse {
|
|
1094
1113
|
|
|
1095
1114
|
let { params = {}, url, refresh = false } = option || {};
|
|
1096
|
-
|
|
1115
|
+
|
|
1097
1116
|
if (params.hasOwnProperty('startKey')) {
|
|
1098
1117
|
if (
|
|
1099
1118
|
typeof params.startKey !== 'object' && !Object.keys(params.startKey).length ||
|
|
@@ -1118,41 +1137,10 @@ export default class Skapi {
|
|
|
1118
1137
|
}
|
|
1119
1138
|
}
|
|
1120
1139
|
|
|
1121
|
-
let toHash = (() => {
|
|
1122
|
-
if (params && typeof params === 'object' && Object.keys(params).length) {
|
|
1123
|
-
// hash request parameters
|
|
1124
|
-
let paramsHash = JSON.parse(JSON.stringify(params));
|
|
1125
|
-
|
|
1126
|
-
function orderObjectKeys(obj: Record<string, any>) {
|
|
1127
|
-
function sortObject(obj: Record<string, any>): Record<string, any> {
|
|
1128
|
-
if (typeof obj === 'object' && obj) {
|
|
1129
|
-
return Object.keys(obj).sort().reduce((res, key) => ((res as any)[key] = obj[key], res), {});
|
|
1130
|
-
}
|
|
1131
|
-
return obj;
|
|
1132
|
-
};
|
|
1133
|
-
|
|
1134
|
-
let _obj = sortObject(obj);
|
|
1135
|
-
for (let k in _obj) {
|
|
1136
|
-
if (_obj[k] && typeof _obj[k] === 'object') {
|
|
1137
|
-
_obj[k] = sortObject(obj[k]);
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
return _obj;
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
return JSON.stringify(orderObjectKeys(paramsHash)) + url + this.service;
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
return url + this.service;
|
|
1148
|
-
})();
|
|
1149
|
-
|
|
1150
1140
|
// let hashedParams = createHash('sha256').update(toHash).digest('hex');
|
|
1151
|
-
let hashedParams =
|
|
1141
|
+
let hashedParams = (() => {
|
|
1152
1142
|
if (params && typeof params === 'object' && Object.keys(params).length) {
|
|
1153
1143
|
// hash request parameters
|
|
1154
|
-
let paramsHash = JSON.parse(JSON.stringify(params));
|
|
1155
|
-
|
|
1156
1144
|
function orderObjectKeys(obj: Record<string, any>) {
|
|
1157
1145
|
function sortObject(obj: Record<string, any>): Record<string, any> {
|
|
1158
1146
|
if (typeof obj === 'object' && obj) {
|
|
@@ -1171,11 +1159,12 @@ export default class Skapi {
|
|
|
1171
1159
|
return _obj;
|
|
1172
1160
|
}
|
|
1173
1161
|
|
|
1174
|
-
return JSON.stringify(orderObjectKeys(
|
|
1162
|
+
return url + '/' + JSON.stringify(orderObjectKeys(params));
|
|
1175
1163
|
}
|
|
1176
1164
|
|
|
1177
|
-
return url + this.service;
|
|
1178
|
-
|
|
1165
|
+
return url + '/' + this.service;
|
|
1166
|
+
|
|
1167
|
+
})();
|
|
1179
1168
|
|
|
1180
1169
|
if (refresh && this.__startKey_keys?.[url]?.[hashedParams]) {
|
|
1181
1170
|
// init cache, init startKey
|
|
@@ -1188,7 +1177,8 @@ export default class Skapi {
|
|
|
1188
1177
|
if (Array.isArray(this.__startKey_keys[url][hashedParams]) && this.__startKey_keys[url][hashedParams].length) {
|
|
1189
1178
|
// delete cache of all startkeys
|
|
1190
1179
|
for (let p of this.__startKey_keys[url][hashedParams]) {
|
|
1191
|
-
let hashedParams_cached = hashedParams + sha256(JSON.stringify(p));
|
|
1180
|
+
// let hashedParams_cached = hashedParams + '/' + sha256(JSON.stringify(p));
|
|
1181
|
+
let hashedParams_cached = hashedParams + '/' + JSON.stringify(p);
|
|
1192
1182
|
// let hashedParams_cached = hashedParams + createHash('sha256').update(JSON.stringify(p)).digest('hex');
|
|
1193
1183
|
|
|
1194
1184
|
if (this.__cached_requests?.[url] && this.__cached_requests?.[url]?.[hashedParams_cached]) {
|
|
@@ -1216,7 +1206,7 @@ export default class Skapi {
|
|
|
1216
1206
|
if (last_startKey_key) {
|
|
1217
1207
|
// use last start key
|
|
1218
1208
|
|
|
1219
|
-
if (last_startKey_key === 'end') {
|
|
1209
|
+
if (last_startKey_key === '"end"') { // cached startKeys are stringified
|
|
1220
1210
|
return {
|
|
1221
1211
|
list: [],
|
|
1222
1212
|
startKey: 'end',
|
|
@@ -1226,7 +1216,8 @@ export default class Skapi {
|
|
|
1226
1216
|
|
|
1227
1217
|
else {
|
|
1228
1218
|
// cache_hashedParams += createHash('sha256').update(last_startKey_key).digest('hex');
|
|
1229
|
-
cache_hashedParams += sha256(last_startKey_key);
|
|
1219
|
+
// cache_hashedParams += sha256(last_startKey_key);
|
|
1220
|
+
cache_hashedParams += ('/' + last_startKey_key);
|
|
1230
1221
|
params.startKey = JSON.parse(last_startKey_key);
|
|
1231
1222
|
}
|
|
1232
1223
|
}
|
|
@@ -1456,13 +1447,9 @@ export default class Skapi {
|
|
|
1456
1447
|
option = checkParams(option || {}, {
|
|
1457
1448
|
record_id: 'string',
|
|
1458
1449
|
access_group: ['number', 'private'],
|
|
1459
|
-
table:
|
|
1460
|
-
if (!option?.record_id) {
|
|
1461
|
-
throw new SkapiError('Either "record_id" or "table" should have a value.', { code: 'INVALID_PARAMETER' });
|
|
1462
|
-
}
|
|
1463
|
-
}],
|
|
1450
|
+
table: 'string',
|
|
1464
1451
|
subscription_group: 'number',
|
|
1465
|
-
reference: 'string',
|
|
1452
|
+
reference: ['string', null],
|
|
1466
1453
|
index: {
|
|
1467
1454
|
name: 'string',
|
|
1468
1455
|
value: ['string', 'number', 'boolean']
|
|
@@ -1488,11 +1475,33 @@ export default class Skapi {
|
|
|
1488
1475
|
throw new SkapiError(`"tags" should be type: <string | string[]>`, { code: 'INVALID_PARAMETER' });
|
|
1489
1476
|
},
|
|
1490
1477
|
config: {
|
|
1491
|
-
reference_limit:
|
|
1478
|
+
reference_limit: (v: number) => {
|
|
1479
|
+
if (v === null) {
|
|
1480
|
+
return null;
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
else if (typeof v === 'number') {
|
|
1484
|
+
if (0 > v) {
|
|
1485
|
+
throw new SkapiError(`"reference_limit" should be >= 0`, { code: 'INVALID_PARAMETER' });
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
if (v > 4503599627370546) {
|
|
1489
|
+
throw new SkapiError(`"reference_limit" should be <= 4503599627370546`, { code: 'INVALID_PARAMETER' });
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
return v;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
throw new SkapiError(`"reference_limit" should be type: <number | null>`, { code: 'INVALID_PARAMETER' });
|
|
1496
|
+
},
|
|
1492
1497
|
allow_multiple_reference: 'boolean',
|
|
1493
1498
|
private_access: (v: string | string[]) => {
|
|
1494
1499
|
let param = 'config.private_access';
|
|
1495
1500
|
|
|
1501
|
+
if (v === null) {
|
|
1502
|
+
return null;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1496
1505
|
if (v && typeof v === 'string') {
|
|
1497
1506
|
v = [v];
|
|
1498
1507
|
}
|
|
@@ -1501,7 +1510,7 @@ export default class Skapi {
|
|
|
1501
1510
|
for (let u of v) {
|
|
1502
1511
|
validateUserId(u, `User ID in "${param}"`);
|
|
1503
1512
|
|
|
1504
|
-
if (this.
|
|
1513
|
+
if (this.__user && u === this.__user.user_id) {
|
|
1505
1514
|
throw new SkapiError(`"${param}" should not be the uploader's user ID.`, { code: 'INVALID_PARAMETER' });
|
|
1506
1515
|
}
|
|
1507
1516
|
}
|
|
@@ -1521,6 +1530,10 @@ export default class Skapi {
|
|
|
1521
1530
|
delete option.formData;
|
|
1522
1531
|
delete option.onerror;
|
|
1523
1532
|
|
|
1533
|
+
if (!option?.table && !option?.record_id) {
|
|
1534
|
+
throw new SkapiError('Either "record_id" or "table" should have a value.', { code: 'INVALID_PARAMETER' });
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1524
1537
|
if (option?.index) {
|
|
1525
1538
|
// index name allows periods. white space is invalid.
|
|
1526
1539
|
if (!option.index?.name || typeof option.index?.name !== 'string') {
|
|
@@ -1545,7 +1558,6 @@ export default class Skapi {
|
|
|
1545
1558
|
}
|
|
1546
1559
|
}
|
|
1547
1560
|
|
|
1548
|
-
|
|
1549
1561
|
if (is_admin) {
|
|
1550
1562
|
if (option?.access_group === 'private') {
|
|
1551
1563
|
throw new SkapiError('Service owner cannot write private records.', { code: 'INVALID_REQUEST' });
|
|
@@ -1656,22 +1668,7 @@ export default class Skapi {
|
|
|
1656
1668
|
return v;
|
|
1657
1669
|
}
|
|
1658
1670
|
},
|
|
1659
|
-
tags:
|
|
1660
|
-
if (typeof v === 'string') {
|
|
1661
|
-
return [v];
|
|
1662
|
-
}
|
|
1663
|
-
else if (Array.isArray(v)) {
|
|
1664
|
-
if (v.length > 10) {
|
|
1665
|
-
throw new SkapiError('Cannot query more than 10 tags at once.', { code: 'INVALID_REQUEST' });
|
|
1666
|
-
}
|
|
1667
|
-
for (let s of v) {
|
|
1668
|
-
if (typeof s !== 'string') {
|
|
1669
|
-
throw new SkapiError('Tags should be type: <string | string[]>', { code: 'INVALID_PARAMETER' });
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1672
|
-
return v;
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1671
|
+
tags: 'string'
|
|
1675
1672
|
};
|
|
1676
1673
|
|
|
1677
1674
|
params = checkParams(params || {}, struct, ['table']);
|
|
@@ -1680,73 +1677,11 @@ export default class Skapi {
|
|
|
1680
1677
|
throw new SkapiError('Requires login.', { code: 'INVALID_REQUEST' });
|
|
1681
1678
|
}
|
|
1682
1679
|
|
|
1683
|
-
if (params?.tags) {
|
|
1684
|
-
let tagFetch = [];
|
|
1685
|
-
let getStartKey = fetchOptions?.startKey || null;
|
|
1686
|
-
|
|
1687
|
-
for (let t of params.tags) {
|
|
1688
|
-
let params_copy = JSON.parse(JSON.stringify(params));
|
|
1689
|
-
params_copy.tag = t;
|
|
1690
|
-
delete params_copy.tags;
|
|
1691
|
-
|
|
1692
|
-
let fetchOpt = fetchOptions ? JSON.parse(JSON.stringify(fetchOptions)) : null;
|
|
1693
|
-
if (fetchOpt) {
|
|
1694
|
-
delete fetchOpt.startKey;
|
|
1695
|
-
|
|
1696
|
-
if (getStartKey && getStartKey?.[t]) {
|
|
1697
|
-
fetchOpt.startKey = getStartKey[t];
|
|
1698
|
-
}
|
|
1699
|
-
}
|
|
1700
|
-
|
|
1701
|
-
tagFetch.push(this.request(
|
|
1702
|
-
'get-records',
|
|
1703
|
-
params_copy,
|
|
1704
|
-
Object.assign(
|
|
1705
|
-
{ auth: params.hasOwnProperty('access_group') && (params.access_group === 'private' || params.access_group > 0) ? true : !!this.session },
|
|
1706
|
-
{ fetchOptions: fetchOpt }
|
|
1707
|
-
)));
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
|
-
let list = [];
|
|
1711
|
-
let startKey = {};
|
|
1712
|
-
let res_all = await Promise.all(tagFetch);
|
|
1713
|
-
|
|
1714
|
-
for (let res of res_all) {
|
|
1715
|
-
for (let i in res.list) {
|
|
1716
|
-
if (tagFetch.includes(res.list[i].rec)) {
|
|
1717
|
-
continue;
|
|
1718
|
-
}
|
|
1719
|
-
tagFetch.push(res.list[i]);
|
|
1720
|
-
list.push(normalize_record_data(res.list[i]));
|
|
1721
|
-
};
|
|
1722
|
-
if (res.startKey) {
|
|
1723
|
-
if (Array.isArray(params.tags)) {
|
|
1724
|
-
let tag = params.tags.splice(0, 1);
|
|
1725
|
-
startKey[tag[0]] = res.startKey;
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
|
|
1730
|
-
let endOfList = true;
|
|
1731
|
-
for (let k in startKey) {
|
|
1732
|
-
if (startKey[k] && startKey[k] !== 'end') {
|
|
1733
|
-
endOfList = false;
|
|
1734
|
-
break;
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1737
|
-
|
|
1738
|
-
return {
|
|
1739
|
-
list,
|
|
1740
|
-
endOfList,
|
|
1741
|
-
startKey
|
|
1742
|
-
};
|
|
1743
|
-
}
|
|
1744
|
-
|
|
1745
1680
|
let result = await this.request(
|
|
1746
1681
|
'get-records',
|
|
1747
1682
|
params,
|
|
1748
1683
|
Object.assign(
|
|
1749
|
-
{ auth: params.hasOwnProperty('access_group') && (params.access_group === 'private' || params.access_group > 0) ? true : !!this.
|
|
1684
|
+
{ auth: params.hasOwnProperty('access_group') && (params.access_group === 'private' || params.access_group > 0) ? true : !!this.__user },
|
|
1750
1685
|
{ fetchOptions }
|
|
1751
1686
|
)
|
|
1752
1687
|
);
|
|
@@ -2205,7 +2140,7 @@ export default class Skapi {
|
|
|
2205
2140
|
}
|
|
2206
2141
|
}, ['user_id', 'group']);
|
|
2207
2142
|
|
|
2208
|
-
if (this.
|
|
2143
|
+
if (this.__user && option.user_id === this.__user.user_id) {
|
|
2209
2144
|
throw new SkapiError(`"user_id" cannot be the user's own ID.`, { code: 'INVALID_PARAMETER' });
|
|
2210
2145
|
}
|
|
2211
2146
|
|
|
@@ -2330,7 +2265,7 @@ export default class Skapi {
|
|
|
2330
2265
|
}) || {};
|
|
2331
2266
|
|
|
2332
2267
|
return this.getSubscriptions({
|
|
2333
|
-
subscriber: option.user_id || this.
|
|
2268
|
+
subscriber: option.user_id || this.__user?.user_id,
|
|
2334
2269
|
group: option.group
|
|
2335
2270
|
});
|
|
2336
2271
|
}
|
|
@@ -2348,7 +2283,7 @@ export default class Skapi {
|
|
|
2348
2283
|
}) || {};
|
|
2349
2284
|
|
|
2350
2285
|
let subParams = {
|
|
2351
|
-
subscription: option.user_id || this.
|
|
2286
|
+
subscription: option.user_id || this.__user?.user_id,
|
|
2352
2287
|
group: option.group
|
|
2353
2288
|
};
|
|
2354
2289
|
|
|
@@ -2722,18 +2657,14 @@ export default class Skapi {
|
|
|
2722
2657
|
*/
|
|
2723
2658
|
async resendSignupConfirmation(
|
|
2724
2659
|
/** Redirect url on confirmation success. */
|
|
2725
|
-
redirect:
|
|
2660
|
+
redirect: string
|
|
2726
2661
|
): Promise<string> {
|
|
2727
|
-
if (
|
|
2728
|
-
|
|
2729
|
-
}
|
|
2730
|
-
|
|
2731
|
-
else if (typeof redirect !== 'boolean') {
|
|
2732
|
-
throw new SkapiError('Argument should be type: <boolean | string>.', { code: 'INVALID_REQUEST' });
|
|
2662
|
+
if (!this.__request_signup_confirmation) {
|
|
2663
|
+
throw new SkapiError('Least one login attempt is required.', { code: 'INVALID_REQUEST' });
|
|
2733
2664
|
}
|
|
2734
2665
|
|
|
2735
|
-
if (
|
|
2736
|
-
|
|
2666
|
+
if (redirect) {
|
|
2667
|
+
validateUrl(redirect);
|
|
2737
2668
|
}
|
|
2738
2669
|
|
|
2739
2670
|
let resend = await this.request("confirm-signup", {
|
|
@@ -2742,7 +2673,7 @@ export default class Skapi {
|
|
|
2742
2673
|
});
|
|
2743
2674
|
|
|
2744
2675
|
this.__request_signup_confirmation = null;
|
|
2745
|
-
return resend;
|
|
2676
|
+
return resend; // 'SUCCESS: Signup confirmation E-Mail has been sent.'
|
|
2746
2677
|
}
|
|
2747
2678
|
|
|
2748
2679
|
/**
|
|
@@ -2834,8 +2765,8 @@ export default class Skapi {
|
|
|
2834
2765
|
if (code) {
|
|
2835
2766
|
this.authentication().updateSession({ refreshToken: true }).then(
|
|
2836
2767
|
() => {
|
|
2837
|
-
if (this.
|
|
2838
|
-
this.
|
|
2768
|
+
if (this.__user) {
|
|
2769
|
+
this.__user[attribute + '_verified'] = true;
|
|
2839
2770
|
}
|
|
2840
2771
|
res(`SUCCESS: "${attribute}" is verified.`);
|
|
2841
2772
|
}
|
|
@@ -3049,8 +2980,8 @@ export default class Skapi {
|
|
|
3049
2980
|
async disableAccount(): Promise<string> {
|
|
3050
2981
|
await this.__connection;
|
|
3051
2982
|
|
|
3052
|
-
if (this.
|
|
3053
|
-
for (let s of this.
|
|
2983
|
+
if (this.__user && Array.isArray(this.__user.services)) {
|
|
2984
|
+
for (let s of this.__user.services) {
|
|
3054
2985
|
if (s.active) {
|
|
3055
2986
|
throw new SkapiError('All services needs to be disabled.', { code: 'INVALID_REQUEST' });
|
|
3056
2987
|
}
|
|
@@ -3115,7 +3046,7 @@ export default class Skapi {
|
|
|
3115
3046
|
});
|
|
3116
3047
|
|
|
3117
3048
|
if (params && typeof params === 'object' && !Object.keys(params).length) {
|
|
3118
|
-
return this.
|
|
3049
|
+
return this.__user;
|
|
3119
3050
|
}
|
|
3120
3051
|
|
|
3121
3052
|
if (params.new_password || params.current_password) {
|
|
@@ -3158,10 +3089,10 @@ export default class Skapi {
|
|
|
3158
3089
|
['phone_number_public', 'phone_number_verified', "User's phone number should be verified to set"]
|
|
3159
3090
|
];
|
|
3160
3091
|
|
|
3161
|
-
if (this.
|
|
3092
|
+
if (this.__user) {
|
|
3162
3093
|
for (let c of collision) {
|
|
3163
|
-
if (params[c[0]] && !this.
|
|
3164
|
-
throw new SkapiError(`${c[2]} "${c[0]}" to true.`, { code: '
|
|
3094
|
+
if (params[c[0]] && !this.__user[c[1]]) {
|
|
3095
|
+
throw new SkapiError(`${c[2]} "${c[0]}" to true.`, { code: 'INVALID_REQUEST' });
|
|
3165
3096
|
}
|
|
3166
3097
|
}
|
|
3167
3098
|
}
|
|
@@ -3220,7 +3151,7 @@ export default class Skapi {
|
|
|
3220
3151
|
await this.authentication().updateSession({ refreshToken: true });
|
|
3221
3152
|
}
|
|
3222
3153
|
|
|
3223
|
-
return this.
|
|
3154
|
+
return this.__user;
|
|
3224
3155
|
}
|
|
3225
3156
|
|
|
3226
3157
|
|
|
@@ -3265,13 +3196,13 @@ export default class Skapi {
|
|
|
3265
3196
|
auth: true
|
|
3266
3197
|
};
|
|
3267
3198
|
|
|
3268
|
-
if (option
|
|
3199
|
+
if (option?.private) {
|
|
3269
3200
|
Object.assign(opt, { meta: { '__private__': option.private } });
|
|
3270
3201
|
}
|
|
3271
3202
|
|
|
3272
3203
|
await this.request('post-userdata', form, opt);
|
|
3273
3204
|
await this.authentication().updateSession();
|
|
3274
|
-
return this.
|
|
3205
|
+
return this.__user;
|
|
3275
3206
|
}
|
|
3276
3207
|
|
|
3277
3208
|
/**
|
|
@@ -3507,7 +3438,7 @@ export default class Skapi {
|
|
|
3507
3438
|
|
|
3508
3439
|
let user = result.list[0];
|
|
3509
3440
|
// append user session data
|
|
3510
|
-
Object.assign(user, this.
|
|
3441
|
+
Object.assign(user, this.__user);
|
|
3511
3442
|
|
|
3512
3443
|
user._what_public_see = JSON.parse(JSON.stringify(user));
|
|
3513
3444
|
|
package/src/utils.ts
CHANGED
|
@@ -1,36 +1,34 @@
|
|
|
1
1
|
import SkapiError from "./skapi_error";
|
|
2
2
|
import { RecordData, Form } from "./Types";
|
|
3
3
|
|
|
4
|
-
const sha256: any = function (ascii) {
|
|
5
|
-
// author: https://geraintluff.github.io/sha256/
|
|
6
|
-
|
|
4
|
+
const sha256: any = function sha256(ascii) {
|
|
7
5
|
function rightRotate(value, amount) {
|
|
8
6
|
return (value >>> amount) | (value << (32 - amount));
|
|
9
7
|
};
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
let mathPow = Math.pow;
|
|
10
|
+
let maxWord = mathPow(2, 32);
|
|
11
|
+
let lengthProperty = 'length';
|
|
12
|
+
let i, j; // Used as a counter across the whole file
|
|
13
|
+
let result = '';
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
let words = [];
|
|
16
|
+
let asciiBitLength = ascii[lengthProperty] * 8;
|
|
19
17
|
|
|
20
18
|
//* caching results is optional - remove/add slash from front of this line to toggle
|
|
21
19
|
// Initial hash value: first 32 bits of the fractional parts of the square roots of the first 8 primes
|
|
22
20
|
// (we actually calculate the first 64, but extra values are just ignored)
|
|
23
|
-
|
|
21
|
+
let hash = (sha256 as any).h = (sha256 as any).h || [];
|
|
24
22
|
// Round constants: first 32 bits of the fractional parts of the cube roots of the first 64 primes
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
let k = (sha256 as any).k = (sha256 as any).k || [];
|
|
24
|
+
let primeCounter = k[lengthProperty];
|
|
27
25
|
/*/
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
let hash = [], k = [];
|
|
27
|
+
let primeCounter = 0;
|
|
30
28
|
//*/
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
for (
|
|
30
|
+
let isComposite = {};
|
|
31
|
+
for (let candidate = 2; primeCounter < 64; candidate++) {
|
|
34
32
|
if (!isComposite[candidate]) {
|
|
35
33
|
for (i = 0; i < 313; i += candidate) {
|
|
36
34
|
isComposite[i] = candidate;
|
|
@@ -44,7 +42,9 @@ const sha256: any = function (ascii) {
|
|
|
44
42
|
while (ascii[lengthProperty] % 64 - 56) ascii += '\x00'; // More zero padding
|
|
45
43
|
for (i = 0; i < ascii[lengthProperty]; i++) {
|
|
46
44
|
j = ascii.charCodeAt(i);
|
|
47
|
-
if (j >> 8)
|
|
45
|
+
if (j >> 8) {
|
|
46
|
+
return; // ASCII check: only accept characters in range 0-255
|
|
47
|
+
}
|
|
48
48
|
words[i >> 2] |= j << ((3 - i) % 4) * 8;
|
|
49
49
|
}
|
|
50
50
|
words[words[lengthProperty]] = ((asciiBitLength / maxWord) | 0);
|
|
@@ -52,21 +52,21 @@ const sha256: any = function (ascii) {
|
|
|
52
52
|
|
|
53
53
|
// process each chunk
|
|
54
54
|
for (j = 0; j < words[lengthProperty];) {
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
let w = words.slice(j, j += 16); // The message is expanded into 64 words as part of the iteration
|
|
56
|
+
let oldHash = hash;
|
|
57
57
|
// This is now the undefinedworking hash", often labelled as variables a...g
|
|
58
58
|
// (we have to truncate as well, otherwise extra entries at the end accumulate
|
|
59
59
|
hash = hash.slice(0, 8);
|
|
60
60
|
|
|
61
61
|
for (i = 0; i < 64; i++) {
|
|
62
|
-
|
|
62
|
+
let i2 = i + j;
|
|
63
63
|
// Expand the message into 64 words
|
|
64
64
|
// Used below if
|
|
65
|
-
|
|
65
|
+
let w15 = w[i - 15], w2 = w[i - 2];
|
|
66
66
|
|
|
67
67
|
// Iterate
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
let a = hash[0], e = hash[4];
|
|
69
|
+
let temp1 = hash[7]
|
|
70
70
|
+ (rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25)) // S1
|
|
71
71
|
+ ((e & hash[5]) ^ ((~e) & hash[6])) // ch
|
|
72
72
|
+ k[i]
|
|
@@ -79,7 +79,7 @@ const sha256: any = function (ascii) {
|
|
|
79
79
|
) | 0
|
|
80
80
|
);
|
|
81
81
|
// This is only used once, so *could* be moved below, but it only saves 4 bytes and makes things unreadble
|
|
82
|
-
|
|
82
|
+
let temp2 = (rightRotate(a, 2) ^ rightRotate(a, 13) ^ rightRotate(a, 22)) // S0
|
|
83
83
|
+ ((a & hash[1]) ^ (a & hash[2]) ^ (hash[1] & hash[2])); // maj
|
|
84
84
|
|
|
85
85
|
hash = [(temp1 + temp2) | 0].concat(hash); // We don't bother trimming off the extra ones, they're harmless as long as we're truncating when we do the slice()
|
|
@@ -93,10 +93,11 @@ const sha256: any = function (ascii) {
|
|
|
93
93
|
|
|
94
94
|
for (i = 0; i < 8; i++) {
|
|
95
95
|
for (j = 3; j + 1; j--) {
|
|
96
|
-
|
|
96
|
+
let b = (hash[i] >> (j * 8)) & 255;
|
|
97
97
|
result += ((b < 16) ? 0 : '') + b.toString(16);
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
+
|
|
100
101
|
return result;
|
|
101
102
|
};
|
|
102
103
|
|
|
@@ -236,7 +237,7 @@ function checkParams(
|
|
|
236
237
|
} catch (err) {
|
|
237
238
|
if (typeof err === 'string' && err.substring(0, 6) === 'BREAK:') {
|
|
238
239
|
// break on BREAK message
|
|
239
|
-
err = err.substring(
|
|
240
|
+
err = err.substring(6);
|
|
240
241
|
let errMsg = (err as string).split(':');
|
|
241
242
|
errToThrow = new SkapiError(errMsg[1], { code: errMsg[0] });
|
|
242
243
|
break;
|
|
@@ -291,6 +292,9 @@ function checkParams(
|
|
|
291
292
|
|
|
292
293
|
val = _params;
|
|
293
294
|
}
|
|
295
|
+
else {
|
|
296
|
+
throw new SkapiError(`Value: ${_params}${isInvalid}`, { code: 'INVALID_PARAMETER' });
|
|
297
|
+
}
|
|
294
298
|
}
|
|
295
299
|
|
|
296
300
|
else if (struct === null) {
|
package/tsconfig.json
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
|
24
24
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
|
25
25
|
/* Language and Environment */
|
|
26
|
-
"target": "
|
|
26
|
+
"target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
|
27
27
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
|
28
28
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
|
29
29
|
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
|
38
38
|
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
|
39
39
|
/* Modules */
|
|
40
|
-
"module": "
|
|
40
|
+
"module": "ES2020", /* Specify what module code is generated. */
|
|
41
41
|
// "rootDir": "./", /* Specify the root folder within your source files. */
|
|
42
42
|
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
|
43
43
|
"moduleResolution": "node",
|