feat: ported totp.js library to zepp quick-js
This commit is contained in:
commit
b67cddf4eb
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules/**
|
||||||
|
dist/*
|
||||||
|
npm-debug.log
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
yarn.lock
|
||||||
|
package-lock.json
|
||||||
|
selenium-debug.log
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
2
app-side/i18n/en-US.po
Normal file
2
app-side/i18n/en-US.po
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
msgid "example"
|
||||||
|
msgstr "This is an example in app-side"
|
13
app-side/index.js
Normal file
13
app-side/index.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { gettext } from 'i18n'
|
||||||
|
|
||||||
|
AppSideService({
|
||||||
|
onInit() {
|
||||||
|
console.log(gettext('example'))
|
||||||
|
},
|
||||||
|
|
||||||
|
onRun() {
|
||||||
|
},
|
||||||
|
|
||||||
|
onDestroy() {
|
||||||
|
}
|
||||||
|
})
|
10
app.js
Normal file
10
app.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
App({
|
||||||
|
globalData: {},
|
||||||
|
onCreate(options) {
|
||||||
|
console.log('app on create invoke')
|
||||||
|
},
|
||||||
|
|
||||||
|
onDestroy(options) {
|
||||||
|
console.log('app on destroy invoke')
|
||||||
|
}
|
||||||
|
})
|
55
app.json
Normal file
55
app.json
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"configVersion": "v3",
|
||||||
|
"app": {
|
||||||
|
"appId": 25087,
|
||||||
|
"appName": "totpfit",
|
||||||
|
"appType": "app",
|
||||||
|
"version": {
|
||||||
|
"code": 1,
|
||||||
|
"name": "1.0.0"
|
||||||
|
},
|
||||||
|
"icon": "icon.png",
|
||||||
|
"vender": "zepp",
|
||||||
|
"description": "TOTP Authenticator for Amazfit devices"
|
||||||
|
},
|
||||||
|
"permissions": [
|
||||||
|
"data:os.device.info"
|
||||||
|
],
|
||||||
|
"runtime": {
|
||||||
|
"apiVersion": {
|
||||||
|
"compatible": "3.0.0",
|
||||||
|
"target": "3.0.0",
|
||||||
|
"minVersion": "3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": {
|
||||||
|
"default": {
|
||||||
|
"module": {
|
||||||
|
"page": {
|
||||||
|
"pages": [
|
||||||
|
"page/index",
|
||||||
|
"page/tip"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app-side": {
|
||||||
|
"path": "app-side/index"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"path": "setting/index"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"platforms": [
|
||||||
|
{
|
||||||
|
"st": "s",
|
||||||
|
"dw": 390
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"i18n": {
|
||||||
|
"en-US": {
|
||||||
|
"appName": "TOTPFit"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultLanguage": "en-US"
|
||||||
|
}
|
BIN
assets/default.b/icon.png
Normal file
BIN
assets/default.b/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
BIN
assets/default.r/icon.png
Normal file
BIN
assets/default.r/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
BIN
assets/default.s/icon.png
Normal file
BIN
assets/default.s/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
1
global.d.ts
vendored
Normal file
1
global.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference path="node_modules/@zeppos/device-types/dist/index.d.ts" />
|
9
jsconfig.json
Normal file
9
jsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es6",
|
||||||
|
"checkJs": true
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "**/node_modules/*"],
|
||||||
|
"files": ["node_modules/@zeppos/device-types/dist/index.d.ts"]
|
||||||
|
}
|
4
lib/thirty-two/.npmignore
Normal file
4
lib/thirty-two/.npmignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*.kpf
|
||||||
|
*~
|
||||||
|
\#*
|
||||||
|
node_modules
|
19
lib/thirty-two/LICENSE.txt
Normal file
19
lib/thirty-two/LICENSE.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2011, Chris Umbel
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
24
lib/thirty-two/Makefile
Normal file
24
lib/thirty-two/Makefile
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Copyright (c) 2011, Chris Umbel
|
||||||
|
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
# THE SOFTWARE.
|
||||||
|
|
||||||
|
SHELL := /bin/bash
|
||||||
|
|
||||||
|
test:
|
||||||
|
jasmine-node spec/
|
15
lib/thirty-two/README.md
Normal file
15
lib/thirty-two/README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# thirty-two
|
||||||
|
|
||||||
|
Implementation of RFC 3548 Base32 encoding/decoding for node.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
npm install thirty-two
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
var base32 = require('thirty-two');
|
||||||
|
base32.encode('node');
|
||||||
|
// output: NZXWIZI=
|
||||||
|
base32.decode('NZXWIZI=');
|
||||||
|
//output: node
|
23
lib/thirty-two/index.js
Normal file
23
lib/thirty-two/index.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2011, Chris Umbel
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export {encode, decode} from './lib/thirty-two/thirty-two.js'
|
128
lib/thirty-two/lib/thirty-two/thirty-two.js
Normal file
128
lib/thirty-two/lib/thirty-two/thirty-two.js
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2011, Chris Umbel
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var charTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||||
|
var byteTable = [
|
||||||
|
0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||||
|
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||||
|
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||||
|
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||||
|
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||||
|
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||||
|
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||||
|
];
|
||||||
|
|
||||||
|
function quintetCount(buff) {
|
||||||
|
var quintets = Math.floor(buff.length / 5);
|
||||||
|
return buff.length % 5 === 0 ? quintets: quintets + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function encode(plain) {
|
||||||
|
if(!Buffer.isBuffer(plain)){
|
||||||
|
plain = new Buffer(plain);
|
||||||
|
}
|
||||||
|
var i = 0;
|
||||||
|
var j = 0;
|
||||||
|
var shiftIndex = 0;
|
||||||
|
var digit = 0;
|
||||||
|
var encoded = new Buffer(quintetCount(plain) * 8);
|
||||||
|
|
||||||
|
/* byte by byte isn't as pretty as quintet by quintet but tests a bit
|
||||||
|
faster. will have to revisit. */
|
||||||
|
while(i < plain.length) {
|
||||||
|
var current = plain[i];
|
||||||
|
|
||||||
|
if(shiftIndex > 3) {
|
||||||
|
digit = current & (0xff >> shiftIndex);
|
||||||
|
shiftIndex = (shiftIndex + 5) % 8;
|
||||||
|
digit = (digit << shiftIndex) | ((i + 1 < plain.length) ?
|
||||||
|
plain[i + 1] : 0) >> (8 - shiftIndex);
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
digit = (current >> (8 - (shiftIndex + 5))) & 0x1f;
|
||||||
|
shiftIndex = (shiftIndex + 5) % 8;
|
||||||
|
if(shiftIndex === 0) i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
encoded[j] = charTable.charCodeAt(digit);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = j; i < encoded.length; i++) {
|
||||||
|
encoded[i] = 0x3d; //'='.charCodeAt(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoded;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function decode(encoded) {
|
||||||
|
var shiftIndex = 0;
|
||||||
|
var plainDigit = 0;
|
||||||
|
var plainChar;
|
||||||
|
var plainPos = 0;
|
||||||
|
if(!Buffer.isBuffer(encoded)){
|
||||||
|
encoded = new Buffer(encoded);
|
||||||
|
}
|
||||||
|
var decoded = new Buffer(Math.ceil(encoded.length * 5 / 8));
|
||||||
|
|
||||||
|
/* byte by byte isn't as pretty as octet by octet but tests a bit
|
||||||
|
faster. will have to revisit. */
|
||||||
|
for(var i = 0; i < encoded.length; i++) {
|
||||||
|
if(encoded[i] === 0x3d){ //'='
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var encodedByte = encoded[i] - 0x30;
|
||||||
|
|
||||||
|
if(encodedByte < byteTable.length) {
|
||||||
|
plainDigit = byteTable[encodedByte];
|
||||||
|
|
||||||
|
if(shiftIndex <= 3) {
|
||||||
|
shiftIndex = (shiftIndex + 5) % 8;
|
||||||
|
|
||||||
|
if(shiftIndex === 0) {
|
||||||
|
plainChar |= plainDigit;
|
||||||
|
decoded[plainPos] = plainChar;
|
||||||
|
plainPos++;
|
||||||
|
plainChar = 0;
|
||||||
|
} else {
|
||||||
|
plainChar |= 0xff & (plainDigit << (8 - shiftIndex));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
shiftIndex = (shiftIndex + 5) % 8;
|
||||||
|
plainChar |= 0xff & (plainDigit >>> shiftIndex);
|
||||||
|
decoded[plainPos] = plainChar;
|
||||||
|
plainPos++;
|
||||||
|
|
||||||
|
plainChar = 0xff & (plainDigit << (8 - shiftIndex));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid input - it is not base32 encoded string');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return decoded.slice(0, plainPos);
|
||||||
|
};
|
15
lib/thirty-two/package.json
Normal file
15
lib/thirty-two/package.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "thirty-two",
|
||||||
|
"description": "Implementation RFC 3548 Base32 encoding/decoding for node.",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.2.6"
|
||||||
|
},
|
||||||
|
"author": "Chris Umbel <chris@chrisumbel.com>",
|
||||||
|
"keywords": ["base32", "encoding"],
|
||||||
|
"main": "./lib/thirty-two/index.js",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/chrisumbel/thirty-two.git"
|
||||||
|
}
|
||||||
|
}
|
63
lib/thirty-two/spec/thirty-two_spec.js
Normal file
63
lib/thirty-two/spec/thirty-two_spec.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2011, Chris Umbel
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
if(!expect){
|
||||||
|
function expect(a){
|
||||||
|
return {
|
||||||
|
toBe: function(b){
|
||||||
|
require('assert').strictEqual(a, b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var base32 = require('../lib/thirty-two/');
|
||||||
|
|
||||||
|
describe('thirty-two', function() {
|
||||||
|
it('should encode', function() {
|
||||||
|
expect(base32.encode('a').toString()).toBe('ME======');
|
||||||
|
expect(base32.encode('be').toString()).toBe('MJSQ====');
|
||||||
|
expect(base32.encode('bee').toString()).toBe('MJSWK===');
|
||||||
|
expect(base32.encode('beer').toString()).toBe('MJSWK4Q=');
|
||||||
|
expect(base32.encode('beers').toString()).toBe('MJSWK4TT');
|
||||||
|
expect(base32.encode('beers 1').toString()).toBe('MJSWK4TTEAYQ====');
|
||||||
|
expect(base32.encode('shockingly dismissed').toString()).toBe('ONUG6Y3LNFXGO3DZEBSGS43NNFZXGZLE');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should decode', function() {
|
||||||
|
expect(base32.decode('ME======').toString()).toBe('a');
|
||||||
|
expect(base32.decode('MJSQ====').toString()).toBe('be');
|
||||||
|
expect(base32.decode('ONXW4===').toString()).toBe('son');
|
||||||
|
expect(base32.decode('MJSWK===').toString()).toBe('bee');
|
||||||
|
expect(base32.decode('MJSWK4Q=').toString()).toBe('beer');
|
||||||
|
expect(base32.decode('MJSWK4TT').toString()).toBe('beers');
|
||||||
|
expect(base32.decode('mjswK4TT').toString()).toBe('beers');
|
||||||
|
expect(base32.decode('MJSWK4TTN5XA====').toString()).toBe('beerson');
|
||||||
|
expect(base32.decode('MJSWK4TTEAYQ====').toString()).toBe('beers 1');
|
||||||
|
expect(base32.decode('ONUG6Y3LNFXGO3DZEBSGS43NNFZXGZLE').toString()).toBe('shockingly dismissed');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be binary safe', function() {
|
||||||
|
expect(base32.decode(base32.encode(new Buffer([0x00, 0xff, 0x88]))).toString('hex')).toBe('00ff88');
|
||||||
|
expect(base32.encode(new Buffer("f61e1f998d69151de8334dbe753ab17ae831c13849a6aecd95d0a4e5dc25", 'hex')).toString()).toBe('6YPB7GMNNEKR32BTJW7HKOVRPLUDDQJYJGTK5TMV2CSOLXBF');
|
||||||
|
expect(base32.decode('6YPB7GMNNEKR32BTJW7HKOVRPLUDDQJYJGTK5TMV2CSOLXBF').toString('hex')).toBe('f61e1f998d69151de8334dbe753ab17ae831c13849a6aecd95d0a4e5dc25');
|
||||||
|
});
|
||||||
|
});
|
3
lib/totp.js/.travis.yml
Normal file
3
lib/totp.js/.travis.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "8"
|
5
lib/totp.js/README.md
Normal file
5
lib/totp.js/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# totp.js
|
||||||
|
Two-factor authentication implementation in pure javascript. One-time password generator (HOTP/TOTP) with support for Google Authenticator.
|
||||||
|
|
||||||
|
[](https://travis-ci.org/wuyanxin/totp.js)
|
||||||
|
|
9
lib/totp.js/index.js
Normal file
9
lib/totp.js/index.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: wuyanxin
|
||||||
|
* @Date: 2018-03-21 23:12:14
|
||||||
|
* @Last Modified by: wuyanxin
|
||||||
|
* @Last Modified time: 2018-03-21 23:12:14
|
||||||
|
*/
|
||||||
|
|
||||||
|
export {HOTP} from './lib/hotp.js'
|
||||||
|
export {TOTP} from './lib/totp.js'
|
77
lib/totp.js/lib/hotp.js
Normal file
77
lib/totp.js/lib/hotp.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* @Author: wuyanxin
|
||||||
|
* @Date: 2018-03-21 22:25:37
|
||||||
|
* @Last Modified by: wuyanxin
|
||||||
|
* @Last Modified time: 2018-03-21 22:29:43
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {encode, decode} from '../../thirty-two/index.js'
|
||||||
|
import jsSHA from 'jssha'
|
||||||
|
|
||||||
|
export class HOTP {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} key secret key
|
||||||
|
* @param {*} digit lenth of otp code
|
||||||
|
*/
|
||||||
|
constructor(key, digit = 6) {
|
||||||
|
this.key = key;
|
||||||
|
this.digit = digit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generate secret key
|
||||||
|
* @param {int} len
|
||||||
|
*/
|
||||||
|
static randomKey(len = 16) {
|
||||||
|
const str = Math.random().toString(36);
|
||||||
|
return encode(str).toString().substr(0, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generate a OTP base on HMAC-SHA-1
|
||||||
|
* @param {int} movingFactor counter
|
||||||
|
*/
|
||||||
|
genOTP(movingFactor) {
|
||||||
|
const hmacSha = new jsSHA('SHA-1', 'BYTES');
|
||||||
|
hmacSha.setHMACKey(decode(this.key).toString(), 'BYTES');
|
||||||
|
|
||||||
|
const factorByte = this._factor2ByteText(movingFactor);
|
||||||
|
hmacSha.update(factorByte);
|
||||||
|
|
||||||
|
const hmac_result = hmacSha.getHMAC('BYTES');
|
||||||
|
return this._truncat(hmac_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* verify a OPT code
|
||||||
|
* @param {string} opt opt code
|
||||||
|
* @param {int} movingFactor counter
|
||||||
|
*/
|
||||||
|
verify(opt, movingFactor) {
|
||||||
|
return opt === this.genOTP(movingFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
_truncat(hmac_result) {
|
||||||
|
const offset = hmac_result[19].charCodeAt() & 0xf;
|
||||||
|
const bin_code = (hmac_result[offset].charCodeAt() & 0x7f) << 24
|
||||||
|
| (hmac_result[offset+1].charCodeAt() & 0xff) << 16
|
||||||
|
| (hmac_result[offset+2].charCodeAt() & 0xff) << 8
|
||||||
|
| (hmac_result[offset+3].charCodeAt() & 0xff);
|
||||||
|
let otp = (bin_code % 10 ** this.digit).toString();
|
||||||
|
while (otp.length < this.digit) {
|
||||||
|
otp = '0' + otp;
|
||||||
|
}
|
||||||
|
return otp;
|
||||||
|
}
|
||||||
|
|
||||||
|
_factor2ByteText(movingFactor) {
|
||||||
|
const text = new Array(8);
|
||||||
|
for (let i = text.length - 1; i >= 0; i--) {
|
||||||
|
text[i] = String.fromCharCode(movingFactor & 0xFF);
|
||||||
|
movingFactor >>= 8;
|
||||||
|
}
|
||||||
|
return text.join('');
|
||||||
|
}
|
||||||
|
}
|
24
lib/totp.js/lib/totp.js
Normal file
24
lib/totp.js/lib/totp.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* @Author: wuyanxin
|
||||||
|
* @Date: 2018-03-21 22:25:42
|
||||||
|
* @Last Modified by: wuyanxin
|
||||||
|
* @Last Modified time: 2018-03-21 22:42:28
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {HOTP} from "./hotp.js";
|
||||||
|
|
||||||
|
export class TOTP extends HOTP {
|
||||||
|
constructor(key){
|
||||||
|
super(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
genOTP(timeStep = 30, t0 = 0) {
|
||||||
|
const T = Math.floor((Date.now() / 1000 - t0) / timeStep);
|
||||||
|
return super.genOTP(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
verify(otp, timeStep = 30, t0 = 0) {
|
||||||
|
return otp === this.genOTP(timeStep, t0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
lib/totp.js/package.json
Normal file
33
lib/totp.js/package.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "totp.js",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "Two-factor authentication implementation in pure javascript. One-time password generator (HOTP/TOTP) with support for Google Authenticator. ",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "./node_modules/.bin/mocha"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/wuyanxin/totp.js.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"otp",
|
||||||
|
"hotp",
|
||||||
|
"totp",
|
||||||
|
"Two-factor authentication",
|
||||||
|
"Google authenticator"
|
||||||
|
],
|
||||||
|
"author": "wuyanxin",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/wuyanxin/totp.js/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/wuyanxin/totp.js#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"jssha": "^2.3.1",
|
||||||
|
"thirty-two": "^1.0.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"mocha": "^5.0.4"
|
||||||
|
}
|
||||||
|
}
|
17
package.json
Normal file
17
package.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "totpfit",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "TOTP Authenticator for Amazfit devices",
|
||||||
|
"main": "app.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"@zeppos/device-types": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jssha": "^3.3.1"
|
||||||
|
}
|
||||||
|
}
|
2
page/i18n/en-US.po
Normal file
2
page/i18n/en-US.po
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
msgid "example"
|
||||||
|
msgstr "This is an example in device"
|
35
page/index.js
Normal file
35
page/index.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { getDeviceInfo } from '@zos/device'
|
||||||
|
import { push } from '@zos/router'
|
||||||
|
import { createWidget, widget } from '@zos/ui'
|
||||||
|
|
||||||
|
import {TOTP} from '../lib/totp.js/lib/totp.js'
|
||||||
|
|
||||||
|
Page({
|
||||||
|
build() {
|
||||||
|
|
||||||
|
const totp = new TOTP('asdasd')
|
||||||
|
|
||||||
|
const {width, height} = getDeviceInfo()
|
||||||
|
createWidget(widget.TEXT, {
|
||||||
|
x: width / 2 - 30,
|
||||||
|
y: height / 2 - 60,
|
||||||
|
text: totp.genOTP()
|
||||||
|
})
|
||||||
|
createWidget(widget.BUTTON,{
|
||||||
|
x: width / 2 - 40,
|
||||||
|
y: height / 2 - 20,
|
||||||
|
w: 80,
|
||||||
|
h: 80,
|
||||||
|
text: '+',
|
||||||
|
radius: 50,
|
||||||
|
text_size: 40,
|
||||||
|
normal_color: 0x303030,
|
||||||
|
press_color: 0x181c18,
|
||||||
|
click_func: () => {
|
||||||
|
push({
|
||||||
|
url: 'page/tip'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
6
page/index.s.layout.js
Normal file
6
page/index.s.layout.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { px } from "@zos/utils";
|
||||||
|
|
||||||
|
export const TEXT_STYLE = {
|
||||||
|
x: px(0),
|
||||||
|
y: px(0),
|
||||||
|
}
|
29
page/tip.js
Normal file
29
page/tip.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { createWidget, widget, align } from "@zos/ui";
|
||||||
|
import { getDeviceInfo } from "@zos/device";
|
||||||
|
import { onGesture, GESTURE_LEFT } from '@zos/interaction'
|
||||||
|
import { back } from "@zos/router";
|
||||||
|
Page({
|
||||||
|
onInit(){
|
||||||
|
onGesture({
|
||||||
|
callback(event) {
|
||||||
|
if(event === GESTURE_LEFT){
|
||||||
|
back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
build() {
|
||||||
|
console.log("Page tip opened")
|
||||||
|
const {width, height} = getDeviceInfo()
|
||||||
|
createWidget(widget.TEXT, {
|
||||||
|
x: 0,
|
||||||
|
w: width,
|
||||||
|
h: height,
|
||||||
|
color: 0xffffff,
|
||||||
|
text_size: 30,
|
||||||
|
align_h: align.CENTER_H,
|
||||||
|
align_v: align.CENTER_V,
|
||||||
|
text: 'To add TOTP record open\n settings on Zepp app'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
2
setting/i18n/en-US.po
Normal file
2
setting/i18n/en-US.po
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
msgid "example"
|
||||||
|
msgstr "This is an example in app-side"
|
7
setting/index.js
Normal file
7
setting/index.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { gettext } from 'i18n'
|
||||||
|
|
||||||
|
AppSettingsPage({
|
||||||
|
build() {
|
||||||
|
console.log(gettext('example'))
|
||||||
|
}
|
||||||
|
})
|
Loading…
x
Reference in New Issue
Block a user