commit b67cddf4eb3dcb2e58a028653780385b6607a5b4 Author: Савелий Савенок <56991906+Lisoveliy@users.noreply.github.com> Date: Sat Nov 9 16:37:03 2024 +0300 feat: ported totp.js library to zepp quick-js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e21f7f --- /dev/null +++ b/.gitignore @@ -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 \ No newline at end of file diff --git a/app-side/i18n/en-US.po b/app-side/i18n/en-US.po new file mode 100644 index 0000000..9eabe48 --- /dev/null +++ b/app-side/i18n/en-US.po @@ -0,0 +1,2 @@ +msgid "example" +msgstr "This is an example in app-side" \ No newline at end of file diff --git a/app-side/index.js b/app-side/index.js new file mode 100644 index 0000000..1e298b2 --- /dev/null +++ b/app-side/index.js @@ -0,0 +1,13 @@ +import { gettext } from 'i18n' + +AppSideService({ + onInit() { + console.log(gettext('example')) + }, + + onRun() { + }, + + onDestroy() { + } +}) diff --git a/app.js b/app.js new file mode 100644 index 0000000..13d6c22 --- /dev/null +++ b/app.js @@ -0,0 +1,10 @@ +App({ + globalData: {}, + onCreate(options) { + console.log('app on create invoke') + }, + + onDestroy(options) { + console.log('app on destroy invoke') + } +}) \ No newline at end of file diff --git a/app.json b/app.json new file mode 100644 index 0000000..62100cc --- /dev/null +++ b/app.json @@ -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" +} diff --git a/assets/default.b/icon.png b/assets/default.b/icon.png new file mode 100644 index 0000000..5a8e20b Binary files /dev/null and b/assets/default.b/icon.png differ diff --git a/assets/default.r/icon.png b/assets/default.r/icon.png new file mode 100644 index 0000000..5a8e20b Binary files /dev/null and b/assets/default.r/icon.png differ diff --git a/assets/default.s/icon.png b/assets/default.s/icon.png new file mode 100644 index 0000000..5a8e20b Binary files /dev/null and b/assets/default.s/icon.png differ diff --git a/global.d.ts b/global.d.ts new file mode 100644 index 0000000..ead47d2 --- /dev/null +++ b/global.d.ts @@ -0,0 +1 @@ +/// diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..1bd80d8 --- /dev/null +++ b/jsconfig.json @@ -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"] +} diff --git a/lib/thirty-two/.npmignore b/lib/thirty-two/.npmignore new file mode 100644 index 0000000..3ee8de4 --- /dev/null +++ b/lib/thirty-two/.npmignore @@ -0,0 +1,4 @@ +*.kpf +*~ +\#* +node_modules diff --git a/lib/thirty-two/LICENSE.txt b/lib/thirty-two/LICENSE.txt new file mode 100644 index 0000000..364e7fa --- /dev/null +++ b/lib/thirty-two/LICENSE.txt @@ -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. \ No newline at end of file diff --git a/lib/thirty-two/Makefile b/lib/thirty-two/Makefile new file mode 100644 index 0000000..6011230 --- /dev/null +++ b/lib/thirty-two/Makefile @@ -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/ diff --git a/lib/thirty-two/README.md b/lib/thirty-two/README.md new file mode 100644 index 0000000..fd81e38 --- /dev/null +++ b/lib/thirty-two/README.md @@ -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 diff --git a/lib/thirty-two/index.js b/lib/thirty-two/index.js new file mode 100644 index 0000000..e0eebe2 --- /dev/null +++ b/lib/thirty-two/index.js @@ -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' \ No newline at end of file diff --git a/lib/thirty-two/lib/thirty-two/thirty-two.js b/lib/thirty-two/lib/thirty-two/thirty-two.js new file mode 100644 index 0000000..2887dfa --- /dev/null +++ b/lib/thirty-two/lib/thirty-two/thirty-two.js @@ -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); +}; diff --git a/lib/thirty-two/package.json b/lib/thirty-two/package.json new file mode 100644 index 0000000..fc341c7 --- /dev/null +++ b/lib/thirty-two/package.json @@ -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 ", + "keywords": ["base32", "encoding"], + "main": "./lib/thirty-two/index.js", + "repository": { + "type": "git", + "url": "git://github.com/chrisumbel/thirty-two.git" + } +} diff --git a/lib/thirty-two/spec/thirty-two_spec.js b/lib/thirty-two/spec/thirty-two_spec.js new file mode 100644 index 0000000..a0e0c0a --- /dev/null +++ b/lib/thirty-two/spec/thirty-two_spec.js @@ -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'); + }); +}); diff --git a/lib/totp.js/.travis.yml b/lib/totp.js/.travis.yml new file mode 100644 index 0000000..efb0983 --- /dev/null +++ b/lib/totp.js/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: + - "8" diff --git a/lib/totp.js/README.md b/lib/totp.js/README.md new file mode 100644 index 0000000..4cfac1e --- /dev/null +++ b/lib/totp.js/README.md @@ -0,0 +1,5 @@ +# totp.js +Two-factor authentication implementation in pure javascript. One-time password generator (HOTP/TOTP) with support for Google Authenticator. + +[![Build Status](https://travis-ci.org/wuyanxin/totp.js.svg?branch=master)](https://travis-ci.org/wuyanxin/totp.js) + diff --git a/lib/totp.js/index.js b/lib/totp.js/index.js new file mode 100644 index 0000000..17fed34 --- /dev/null +++ b/lib/totp.js/index.js @@ -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' diff --git a/lib/totp.js/lib/hotp.js b/lib/totp.js/lib/hotp.js new file mode 100644 index 0000000..3c1c9b9 --- /dev/null +++ b/lib/totp.js/lib/hotp.js @@ -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(''); + } +} \ No newline at end of file diff --git a/lib/totp.js/lib/totp.js b/lib/totp.js/lib/totp.js new file mode 100644 index 0000000..ebae234 --- /dev/null +++ b/lib/totp.js/lib/totp.js @@ -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); + } + +} \ No newline at end of file diff --git a/lib/totp.js/package.json b/lib/totp.js/package.json new file mode 100644 index 0000000..798a589 --- /dev/null +++ b/lib/totp.js/package.json @@ -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" + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5dac011 --- /dev/null +++ b/package.json @@ -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" + } +} diff --git a/page/i18n/en-US.po b/page/i18n/en-US.po new file mode 100644 index 0000000..e168a33 --- /dev/null +++ b/page/i18n/en-US.po @@ -0,0 +1,2 @@ +msgid "example" +msgstr "This is an example in device" \ No newline at end of file diff --git a/page/index.js b/page/index.js new file mode 100644 index 0000000..d1a6b86 --- /dev/null +++ b/page/index.js @@ -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' + }) + } + }) + } +}) diff --git a/page/index.s.layout.js b/page/index.s.layout.js new file mode 100644 index 0000000..7bf6175 --- /dev/null +++ b/page/index.s.layout.js @@ -0,0 +1,6 @@ +import { px } from "@zos/utils"; + +export const TEXT_STYLE = { + x: px(0), + y: px(0), +} diff --git a/page/tip.js b/page/tip.js new file mode 100644 index 0000000..29ab95a --- /dev/null +++ b/page/tip.js @@ -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' + }) + } +}) \ No newline at end of file diff --git a/setting/i18n/en-US.po b/setting/i18n/en-US.po new file mode 100644 index 0000000..9eabe48 --- /dev/null +++ b/setting/i18n/en-US.po @@ -0,0 +1,2 @@ +msgid "example" +msgstr "This is an example in app-side" \ No newline at end of file diff --git a/setting/index.js b/setting/index.js new file mode 100644 index 0000000..eaf57c2 --- /dev/null +++ b/setting/index.js @@ -0,0 +1,7 @@ +import { gettext } from 'i18n' + +AppSettingsPage({ + build() { + console.log(gettext('example')) + } +}) \ No newline at end of file