Compare commits
	
		
			No commits in common. "73ea81af549df7c4a659d9907d743e1b40c1d7e1" and "b4df58765d154b212496a4adbe4abc2e0fa3c885" have entirely different histories.
		
	
	
		
			73ea81af54
			...
			b4df58765d
		
	
		
| @ -1 +0,0 @@ | |||||||
| tabWidth: 4 |  | ||||||
| @ -6,12 +6,11 @@ AppSideService( | |||||||
|       onInit(){ |       onInit(){ | ||||||
| 
 | 
 | ||||||
|       }, |       }, | ||||||
|       onRequest(request, response){ |       onRequest(req, res){ | ||||||
|         if(request.method === 'totps'){ |         if(req.method === 'totps'){ | ||||||
|           response(null, settings.settingsStorage.getItem('TOTPs')) |           res(null, settings.settingsStorage.getItem('TOTPs')) | ||||||
|         } |         } | ||||||
|       }, |       } | ||||||
|       onSettingsChange(){ } |  | ||||||
|     } |     } | ||||||
|   ) |   ) | ||||||
| ) | ) | ||||||
							
								
								
									
										19
									
								
								app.js
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								app.js
									
									
									
									
									
								
							| @ -1,11 +1,14 @@ | |||||||
| import { BaseApp } from "@zeppos/zml/base-app"; | import { BaseApp } from "@zeppos/zml/base-app" | ||||||
| 
 | 
 | ||||||
| App( | App( | ||||||
|     BaseApp({ |   BaseApp( | ||||||
|         globalData: { |     { | ||||||
|             TOTPS: [], |       globalData: { | ||||||
|         }, |         TOTPS: [] | ||||||
|         onCreate() {}, |       }, | ||||||
|         onDestroy() {}, |       onCreate() { | ||||||
|  |       },     | ||||||
|  |       onDestroy() { | ||||||
|  |       } | ||||||
|     }) |     }) | ||||||
| ); | ) | ||||||
							
								
								
									
										5
									
								
								app.json
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								app.json
									
									
									
									
									
								
							| @ -6,14 +6,15 @@ | |||||||
|     "appType": "app", |     "appType": "app", | ||||||
|     "version": { |     "version": { | ||||||
|       "code": 1, |       "code": 1, | ||||||
|       "name": "1.0.1" |       "name": "1.0.0" | ||||||
|     }, |     }, | ||||||
|     "icon": "icon.png", |     "icon": "icon.png", | ||||||
|     "vender": "zepp", |     "vender": "zepp", | ||||||
|     "description": "TOTP Authenticator for Amazfit devices" |     "description": "TOTP Authenticator for Amazfit devices" | ||||||
|   }, |   }, | ||||||
|   "permissions": [ |   "permissions": [ | ||||||
|     "data:os.device.info" |     "data:os.device.info", | ||||||
|  |     "device:os.local_storage" | ||||||
|   ], |   ], | ||||||
|   "runtime": { |   "runtime": { | ||||||
|     "apiVersion": { |     "apiVersion": { | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ export function getHOTP(counter, secret, digits = 6, hashType = 'SHA-1'){ | |||||||
|     rawDataCounter.setUint32(4, counter) |     rawDataCounter.setUint32(4, counter) | ||||||
|      |      | ||||||
|     const bCounter = new Uint8Array(rawDataCounter.buffer) |     const bCounter = new Uint8Array(rawDataCounter.buffer) | ||||||
|  |     console.log(bCounter) | ||||||
|     const bSecret = new Uint8Array(decode(secret).match(/.{1,2}/g).map(chunk => parseInt(chunk, 16))); //confirmed
 |     const bSecret = new Uint8Array(decode(secret).match(/.{1,2}/g).map(chunk => parseInt(chunk, 16))); //confirmed
 | ||||||
|      |      | ||||||
|     //Stage 2: Hash data
 |     //Stage 2: Hash data
 | ||||||
|  | |||||||
| @ -1,42 +1,47 @@ | |||||||
| import { RenderAddButton } from "./render/totpRenderer"; | import { RenderAddButton } from './render/totpRenderer' | ||||||
| import { initLoop } from "./render/index/renderer"; | import { initLoop } from './render/index/renderer' | ||||||
| import { BasePage } from "@zeppos/zml/base-page"; | import { BasePage } from '@zeppos/zml/base-page' | ||||||
|  | import { LocalStorage } from "@zos/storage" | ||||||
| 
 | 
 | ||||||
| const app = getApp(); | const localStorage = new LocalStorage() | ||||||
|  | const app = getApp() | ||||||
| let waitForFetch = true; | let waitForFetch = true; | ||||||
| Page( | Page( | ||||||
|     BasePage({ | 	BasePage({ | ||||||
|         onInit() { | 		onInit() { | ||||||
|             this.getTOTPData() | 			this.getTOTPData().then((x) => { | ||||||
|                 .then((x) => { | 				console.log(x) | ||||||
|                     app._options.globalData.TOTPS = JSON.parse(x) ?? []; | 				localStorage.setItem('TOTPs', x ?? []) | ||||||
|                     this.initPage(); | 				app._options.globalData.TOTPS = x ?? [] | ||||||
|                 }) | 				this.initPage(); | ||||||
|                 .catch((x) => { | 			}) | ||||||
|                     app._options.globalData.TOTPS = []; | 			.catch(() => { | ||||||
|                     this.initPage(); | 			 	app._options.globalData.TOTPS = localStorage.getItem('TOTPs') ?? [] | ||||||
|                 }); | 				this.initPage() | ||||||
|         }, | 			 }) | ||||||
|         build() { | 		}, | ||||||
|             let fetch = setInterval(() => { | 		build() { | ||||||
|                 if (waitForFetch) return; | 			let fetch = setInterval(() => { | ||||||
|  | 				if(waitForFetch) | ||||||
|  | 					return; | ||||||
| 
 | 
 | ||||||
|                 clearInterval(fetch); | 				clearInterval(fetch); | ||||||
|                 const buffer = app._options.globalData.TOTPS; | 				const buffer = app._options.globalData.TOTPS | ||||||
|                 if (buffer.length < 1) { | 				if (buffer.length < 1){ | ||||||
|                     RenderAddButton("page/tip"); | 					RenderAddButton('page/tip') | ||||||
|                 } else { | 				} | ||||||
|                     initLoop(buffer); | 				else { | ||||||
|                 } | 					initLoop(buffer) | ||||||
|             }, 100); | 				} | ||||||
|         }, | 			}, 100); | ||||||
|         initPage() { | 		}, | ||||||
|             waitForFetch = false; | 		initPage() { | ||||||
|         }, | 			waitForFetch = false; | ||||||
|         getTOTPData() { | 		}, | ||||||
|             return this.request({ | 		getTOTPData() { | ||||||
|                 method: "totps", | 			return this.request({ | ||||||
|             }); | 				method: 'totps' | ||||||
|         }, | 			}) | ||||||
|     }) | 		} | ||||||
| ); | 	}) | ||||||
|  | ) | ||||||
| @ -1,6 +1,6 @@ | |||||||
| import { px } from "@zos/utils"; | import { px } from "@zos/utils"; | ||||||
| 
 | 
 | ||||||
| export const TEXT_STYLE = { | export const TEXT_STYLE = { | ||||||
|     x: px(0), |   x: px(0), | ||||||
|     y: px(0), |   y: px(0), | ||||||
| }; | } | ||||||
|  | |||||||
| @ -1,57 +1,46 @@ | |||||||
| import { prop } from "@zos/ui"; | import { prop } from "@zos/ui"; | ||||||
| import { TOTP } from "../../../lib/totp-quickjs"; | import { TOTP } from "../../../lib/totp-quickjs"; | ||||||
| import { | import { RenderExpireBar, RenderOTPValue, RenderTOTPContainer } from '../totpRenderer' | ||||||
|     RenderExpireBar, |  | ||||||
|     RenderOTPValue, |  | ||||||
|     RenderTOTPContainer, |  | ||||||
| } from "../totpRenderer"; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  *  |  *  | ||||||
|  * @param {Array<TOTP>} buffer  |  * @param {Array<TOTP>} buffer  | ||||||
|  */ |  */ | ||||||
| export function initLoop(buffer) { | export function initLoop(buffer) { | ||||||
|     renderContainers(buffer); |     renderContainers(buffer) | ||||||
|     renderTOTPs(buffer); |     renderTOTPs(buffer) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function renderContainers(buffer) { | function renderContainers(buffer) { | ||||||
|     for (let i = 0; i < buffer.length; i++) { |     for (let i = 0; i < buffer.length; i++) { | ||||||
|         RenderTOTPContainer(i, buffer[i].issuer, buffer[i].client); |         RenderTOTPContainer(i, buffer[i].issuer, buffer[i].client) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| const renderData = []; | const renderData = [] | ||||||
| 
 | 
 | ||||||
| function renderTOTPs(buffer) { | function renderTOTPs(buffer) { | ||||||
|     for (let i = 0; i < buffer.length; i++) { |     for (let i = 0; i < buffer.length; i++) { | ||||||
|         let otpData = TOTP.copy(buffer[i]).getOTP(); |         let otpData = TOTP.copy(buffer[i]).getOTP() | ||||||
|  |         console.log(otpData.otp) | ||||||
|         renderData[i] = { |         renderData[i] = { | ||||||
|             OTP: RenderOTPValue(i, otpData.otp), |             OTP: RenderOTPValue(i, otpData.otp), | ||||||
|             expireBar: RenderExpireBar( |             expireBar: RenderExpireBar(i, otpData.createdTime, buffer[i].fetchTime) | ||||||
|                 i, |         } | ||||||
|                 otpData.createdTime, |  | ||||||
|                 buffer[i].fetchTime |  | ||||||
|             ), |  | ||||||
|         }; |  | ||||||
|         setInterval(() => { |         setInterval(() => { | ||||||
|             const expireDif = Math.abs( |             const expireDif = Math.abs((((Date.now() - otpData.createdTime) / 1000) | ||||||
|                 (Date.now() - otpData.createdTime) / |                 / buffer[i].fetchTime) - 1) | ||||||
|                     1000 / |  | ||||||
|                     buffer[i].fetchTime - |  | ||||||
|                     1 |  | ||||||
|             ); |  | ||||||
| 
 | 
 | ||||||
|             renderData[i].expireBar.setProperty(prop.MORE, { |             renderData[i].expireBar.setProperty(prop.MORE, { | ||||||
|                 end_angle: expireDif * 360 - 90, |                 end_angle: (expireDif * 360) - 90, | ||||||
|                 color: expireDif > 0.25 ? 0x1ca9c9 : 0xfa0404, |                 color: expireDif > 0.25 ? 0x1ca9c9 : 0xfa0404, | ||||||
|             }); |             }) | ||||||
|              |              | ||||||
|             if (otpData.expireTime < Date.now()) { |             if (otpData.expireTime < Date.now()) { | ||||||
|                 otpData = TOTP.copy(buffer[i]).getOTP(); |                 otpData = TOTP.copy(buffer[i]).getOTP() | ||||||
|                 renderData[i].OTP.setProperty(prop.MORE, { |                 renderData[i].OTP.setProperty(prop.MORE, { | ||||||
|                     text: otpData.otp, |                     text: otpData.otp | ||||||
|                 }); |                 }) | ||||||
|             } |             } | ||||||
|         }, 50); |         }, 50) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1,18 +1,18 @@ | |||||||
| import { getDeviceInfo } from "@zos/device"; | import { getDeviceInfo } from '@zos/device' | ||||||
| import { push } from "@zos/router"; | import { push } from '@zos/router' | ||||||
| import { createWidget, widget, align, text_style } from "@zos/ui"; | import { createWidget, widget, align, text_style } from '@zos/ui' | ||||||
| 
 | 
 | ||||||
| //Renderer module for TOTPs page
 | //Renderer module for TOTPs page
 | ||||||
| 
 | 
 | ||||||
| const { width, height } = getDeviceInfo(); | const { width, height } = getDeviceInfo() | ||||||
| const buttonWidth = width - width / 20; //Width of container
 | const buttonWidth = width - width / 20 //Width of container
 | ||||||
| const buttonHeight = height / 4; //Height of container
 | const buttonHeight = height / 4 //Height of container
 | ||||||
| const containerColor = 0x303030; //Color of container
 | const containerColor = 0x303030 //Color of container
 | ||||||
| const containerRadius = 20; //Corner radius of container
 | const containerRadius = 20 //Corner radius of container
 | ||||||
| 
 | 
 | ||||||
| const textColor = 0xa0a0a0; //Color of TOTP description text
 | const textColor = 0xa0a0a0 //Color of TOTP description text
 | ||||||
| const textSize = 24; //Size of TOTP description text
 | const textSize = 24 //Size of TOTP description text
 | ||||||
| const statusBarPading = 65; | const statusBarPading = 65 | ||||||
| 
 | 
 | ||||||
| /** Function for render box container for TOTP values | /** Function for render box container for TOTP values | ||||||
|  *  |  *  | ||||||
| @ -21,15 +21,15 @@ const statusBarPading = 65; | |||||||
|  * @param {string} client client of TOTP |  * @param {string} client client of TOTP | ||||||
|  */ |  */ | ||||||
| export function RenderTOTPContainer(position, issuer, client) { | export function RenderTOTPContainer(position, issuer, client) { | ||||||
|     const yPos = getYPos(position); |     const yPos = getYPos(position) | ||||||
|     createWidget(widget.FILL_RECT, { |     createWidget(widget.FILL_RECT, { | ||||||
|         x: width / 2 - buttonWidth / 2, |         x: width / 2 - buttonWidth / 2, | ||||||
|         y: yPos, |         y: yPos, | ||||||
|         w: buttonWidth, |         w: buttonWidth, | ||||||
|         h: buttonHeight, |         h: buttonHeight, | ||||||
|         color: containerColor, |         color: containerColor, | ||||||
|         radius: containerRadius, |         radius: containerRadius | ||||||
|     }); |     }) | ||||||
|     createWidget(widget.TEXT, { |     createWidget(widget.TEXT, { | ||||||
|         x: 0 + (width - buttonWidth) / 2, |         x: 0 + (width - buttonWidth) / 2, | ||||||
|         y: yPos + 10, |         y: yPos + 10, | ||||||
| @ -40,8 +40,8 @@ export function RenderTOTPContainer(position, issuer, client) { | |||||||
|         align_h: align.CENTER_H, |         align_h: align.CENTER_H, | ||||||
|         align_v: align.CENTER_V, |         align_v: align.CENTER_V, | ||||||
|         text_style: text_style.NONE, |         text_style: text_style.NONE, | ||||||
|         text: issuer + ": " + client, |         text: issuer + ': ' + client | ||||||
|     }); |     }) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Render OTP Value on container | /** Render OTP Value on container | ||||||
| @ -51,7 +51,7 @@ export function RenderTOTPContainer(position, issuer, client) { | |||||||
|  * @returns widget with OTP |  * @returns widget with OTP | ||||||
|  */ |  */ | ||||||
| export function RenderOTPValue(position, otpValue) { | export function RenderOTPValue(position, otpValue) { | ||||||
|     const yPos = getYPos(position); |     const yPos = getYPos(position) | ||||||
|     return createWidget(widget.TEXT, { |     return createWidget(widget.TEXT, { | ||||||
|         x: 0, |         x: 0, | ||||||
|         y: yPos + 50, |         y: yPos + 50, | ||||||
| @ -62,8 +62,8 @@ export function RenderOTPValue(position, otpValue) { | |||||||
|         align_h: align.CENTER_H, |         align_h: align.CENTER_H, | ||||||
|         align_v: align.CENTER_V, |         align_v: align.CENTER_V, | ||||||
|         text_style: text_style.NONE, |         text_style: text_style.NONE, | ||||||
|         text: otpValue, |         text: otpValue | ||||||
|     }); |     }) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Render expire bar | /** Render expire bar | ||||||
| @ -74,10 +74,9 @@ export function RenderOTPValue(position, otpValue) { | |||||||
|  * @returns widget with bar |  * @returns widget with bar | ||||||
|  */ |  */ | ||||||
| export function RenderExpireBar(position, createdTime, fetchTime) { | export function RenderExpireBar(position, createdTime, fetchTime) { | ||||||
|     const yPos = getYPos(position); |     const yPos = getYPos(position) | ||||||
|     const expireDif = Math.abs( |     const expireDif = Math.abs((((Date.now() - createdTime) / 1000) | ||||||
|         (Date.now() - createdTime) / 1000 / fetchTime - 1 |         / fetchTime) - 1) | ||||||
|     ); |  | ||||||
|     return createWidget(widget.ARC, { |     return createWidget(widget.ARC, { | ||||||
|         x: buttonWidth - 50, |         x: buttonWidth - 50, | ||||||
|         y: yPos + 52, |         y: yPos + 52, | ||||||
| @ -86,8 +85,8 @@ export function RenderExpireBar(position, createdTime, fetchTime) { | |||||||
|         line_width: 5, |         line_width: 5, | ||||||
|         color: expireDif > 0.25 ? 0x1ca9c9 : 0xfa0404, |         color: expireDif > 0.25 ? 0x1ca9c9 : 0xfa0404, | ||||||
|         start_angle: -90, |         start_angle: -90, | ||||||
|         end_angle: expireDif * 360 - 90, |         end_angle: (expireDif * 360) - 90, | ||||||
|         text: expireDif, |         text: expireDif | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -101,19 +100,17 @@ export function RenderAddButton(pagePath) { | |||||||
|         y: height / 2 - 20, |         y: height / 2 - 20, | ||||||
|         w: 80, |         w: 80, | ||||||
|         h: 80, |         h: 80, | ||||||
|         text: "+", |         text: '+', | ||||||
|         radius: 50, |         radius: 50, | ||||||
|         text_size: 40, |         text_size: 40, | ||||||
|         normal_color: 0x303030, |         normal_color: 0x303030, | ||||||
|         press_color: 0x181c18, |         press_color: 0x181c18, | ||||||
|         click_func: () => { |         click_func: () => { | ||||||
|             push({ |             push({ | ||||||
|                 url: pagePath, |                 url: pagePath | ||||||
|             }); |             }) | ||||||
|         }, |         } | ||||||
|     }); |     }) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getYPos(position) { | function getYPos(position) { return position * (buttonHeight + 10) + statusBarPading } | ||||||
|     return position * (buttonHeight + 10) + statusBarPading; |  | ||||||
| } |  | ||||||
							
								
								
									
										18
									
								
								page/tip.js
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								page/tip.js
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | |||||||
| import { createWidget, widget, align } from "@zos/ui"; | import { createWidget, widget, align } from "@zos/ui"; | ||||||
| import { getDeviceInfo } from "@zos/device"; | import { getDeviceInfo } from "@zos/device"; | ||||||
| import { onGesture, GESTURE_LEFT } from "@zos/interaction"; | import { onGesture, GESTURE_LEFT } from '@zos/interaction' | ||||||
| import { back } from "@zos/router"; | import { back } from "@zos/router"; | ||||||
| import { BasePage } from "@zeppos/zml/base-page"; | import { BasePage } from "@zeppos/zml/base-page"; | ||||||
| Page( | Page( | ||||||
| @ -9,13 +9,13 @@ Page( | |||||||
|             onGesture({ |             onGesture({ | ||||||
|                 callback(event) { |                 callback(event) { | ||||||
|                     if (event === GESTURE_LEFT) { |                     if (event === GESTURE_LEFT) { | ||||||
|                         back(); |                         back() | ||||||
|                     } |                     } | ||||||
|                 }, |                 } | ||||||
|             }); |             }) | ||||||
|         }, |         }, | ||||||
|         build() { |         build() { | ||||||
|             const { width, height } = getDeviceInfo(); |             const { width, height } = getDeviceInfo() | ||||||
|             createWidget(widget.TEXT, { |             createWidget(widget.TEXT, { | ||||||
|                 x: 0, |                 x: 0, | ||||||
|                 w: width, |                 w: width, | ||||||
| @ -24,8 +24,8 @@ Page( | |||||||
|                 text_size: 30, |                 text_size: 30, | ||||||
|                 align_h: align.CENTER_H, |                 align_h: align.CENTER_H, | ||||||
|                 align_v: align.CENTER_V, |                 align_v: align.CENTER_V, | ||||||
|                 text: "To add TOTP record open\n settings on Zepp app", |                 text: 'To add TOTP record open\n settings on Zepp app' | ||||||
|             }); |             }) | ||||||
|         }, |         } | ||||||
|     }) |     }) | ||||||
| ); | ) | ||||||
							
								
								
									
										314
									
								
								setting/index.js
									
									
									
									
									
								
							
							
						
						
									
										314
									
								
								setting/index.js
									
									
									
									
									
								
							| @ -1,172 +1,162 @@ | |||||||
| import { getTOTPByLink } from "./utils/queryParser.js"; | import { getTOTPByLink } from './utils/queryParser.js' | ||||||
| 
 | 
 | ||||||
| let _props = null; | let _props = null; | ||||||
| 
 | 
 | ||||||
| AppSettingsPage({ | AppSettingsPage({ | ||||||
|     build(props) { |   build(props) { | ||||||
|         _props = props; |     _props = props; | ||||||
| 
 | 
 | ||||||
|         const storage = JSON.parse( |     const storage = props.settingsStorage.getItem("TOTPs") ?? [] | ||||||
|             props.settingsStorage.getItem("TOTPs") ?? "[]" |     const totpEntrys = GetTOTPList(storage) | ||||||
|         ); |     const createButton = TextInput({ | ||||||
|         const totpEntrys = GetTOTPList(storage); |       placeholder: "otpauth://", | ||||||
|         const createButton = TextInput({ |       label: "Add new OTP Link", | ||||||
|             placeholder: "otpauth://", |       onChange: (changes) => { | ||||||
|             label: "Add new OTP Link", |         var link = getTOTPByLink(changes) | ||||||
|             onChange: (changes) => { |         if(link == null){ | ||||||
|                 var link = getTOTPByLink(changes); |           console.log("link is invalid") | ||||||
|                 if (link == null) { |           return; | ||||||
|                     console.log("link is invalid"); |         } | ||||||
|                     return; |         storage.push(link) | ||||||
|                 } |         updateStorage(storage) | ||||||
|                 storage.push(link); |       }, | ||||||
|                 updateStorage(storage); |       labelStyle: { | ||||||
|             }, |         backgroundColor: "#14213D", | ||||||
|             labelStyle: { |         display: "flex", | ||||||
|                 backgroundColor: "#14213D", |         alignItems: "center", | ||||||
|                 display: "flex", |         justifyContent: "center", | ||||||
|                 alignItems: "center", |         margin: "10px", | ||||||
|                 justifyContent: "center", |         flexGrow: 1, | ||||||
|                 margin: "10px", |         fontSize: "20px", | ||||||
|                 flexGrow: 1, |         color: "#FFFFFF", | ||||||
|                 fontSize: "20px", |         borderRadius: "5px" | ||||||
|                 color: "#FFFFFF", |       } | ||||||
|                 borderRadius: "5px", |  | ||||||
|             }, |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         var body = Section( |  | ||||||
|             { |  | ||||||
|                 style: { |  | ||||||
|                     backgroundColor: "black", |  | ||||||
|                     minHeight: "100vh", |  | ||||||
|                 }, |  | ||||||
|             }, |  | ||||||
|             [ |  | ||||||
|                 View( |  | ||||||
|                     { |  | ||||||
|                         style: { |  | ||||||
|                             textAlign: "center", |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                     Text( |  | ||||||
|                         { |  | ||||||
|                             align: "center", |  | ||||||
|                             paragraph: true, |  | ||||||
|                             style: { |  | ||||||
|                                 marginBottom: "10px", |  | ||||||
|                                 color: "#fff", |  | ||||||
|                                 fontSize: 23, |  | ||||||
|                                 verticalAlign: "middle", |  | ||||||
|                             }, |  | ||||||
|                         }, |  | ||||||
|                         "TOTPS:" |  | ||||||
|                     ) |  | ||||||
|                 ), |  | ||||||
|                 ...totpEntrys, |  | ||||||
|                 createButton, |  | ||||||
|             ] |  | ||||||
|         ); |  | ||||||
|         return body; |  | ||||||
|     }, |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| function GetTOTPList(storage) { |  | ||||||
|     let totpEntrys = []; |  | ||||||
|     let counter = 0; |  | ||||||
|     storage.forEach((element) => { |  | ||||||
|         const elementId = counter; |  | ||||||
|         const textInput = TextInput({ |  | ||||||
|             placeholder: "otpauth://", |  | ||||||
|             label: "Change OTP link", |  | ||||||
|             onChange: (changes) => { |  | ||||||
|                 try { |  | ||||||
|                     storage[elementId] = getTOTPByLink(changes); |  | ||||||
|                     updateStorage(storage); |  | ||||||
|                 } catch (err) { |  | ||||||
|                     console.log(err); |  | ||||||
|                 } |  | ||||||
|             }, |  | ||||||
|             labelStyle: { |  | ||||||
|                 backgroundColor: "#14213D", |  | ||||||
|                 textAlign: "center", |  | ||||||
|                 display: "flex", |  | ||||||
|                 alignItems: "center", |  | ||||||
|                 justifyContent: "center", |  | ||||||
|                 margin: "10px", |  | ||||||
|                 flexGrow: 1, |  | ||||||
|                 fontSize: "20px", |  | ||||||
|                 color: "#E5E5E5", |  | ||||||
|                 borderRadius: "5px", |  | ||||||
|             }, |  | ||||||
|         }); |  | ||||||
|         const textBig = Text( |  | ||||||
|             { |  | ||||||
|                 align: "center", |  | ||||||
|                 style: { |  | ||||||
|                     color: "#ffffff", |  | ||||||
|                     fontSize: "16px", |  | ||||||
|                 }, |  | ||||||
|                 paragraph: true, |  | ||||||
|             }, |  | ||||||
|             `${element.issuer}: ${element.client}` |  | ||||||
|         ); |  | ||||||
|         const delButton = Button({ |  | ||||||
|             onClick: () => { |  | ||||||
|                 storage = storage.filter( |  | ||||||
|                     (x) => storage.indexOf(x) != elementId |  | ||||||
|                 ); |  | ||||||
|                 updateStorage(storage); |  | ||||||
|             }, |  | ||||||
|             style: { |  | ||||||
|                 backgroundColor: "#ba181b", |  | ||||||
|                 fontSize: "18px", |  | ||||||
|                 color: "#ffffff", |  | ||||||
|                 height: "fit-content", |  | ||||||
|                 margin: "10px", |  | ||||||
|             }, |  | ||||||
|             label: "DEL", |  | ||||||
|         }); |  | ||||||
|         const text = Text( |  | ||||||
|             { |  | ||||||
|                 style: { |  | ||||||
|                     color: "#ffffff", |  | ||||||
|                     fontSize: "14px", |  | ||||||
|                 }, |  | ||||||
|                 align: "center", |  | ||||||
|             }, |  | ||||||
|             `${element.hashType} | ${element.digits} digits | ${element.fetchTime} seconds | offset ${element.timeOffset} seconds` |  | ||||||
|         ); |  | ||||||
|         const view = View( |  | ||||||
|             { |  | ||||||
|                 style: { |  | ||||||
|                     textAlign: "center", |  | ||||||
|                     border: "2px solid white", |  | ||||||
|                     borderRadius: "5px", |  | ||||||
|                     margin: "10px", |  | ||||||
|                 }, |  | ||||||
|             }, |  | ||||||
|             [ |  | ||||||
|                 textBig, |  | ||||||
|                 text, |  | ||||||
|                 View( |  | ||||||
|                     { |  | ||||||
|                         style: { |  | ||||||
|                             display: "grid", |  | ||||||
|                             gridTemplateColumns: "1fr 100px", |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                     [textInput, delButton] |  | ||||||
|                 ), |  | ||||||
|             ] |  | ||||||
|         ); |  | ||||||
|         totpEntrys.push({ text: text, view: view }); |  | ||||||
|         counter++; |  | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     return totpEntrys.map((x) => x.view); |     var body = Section( | ||||||
|  |       { | ||||||
|  |         style: { | ||||||
|  |           backgroundColor: "black", | ||||||
|  |           minHeight: "100vh", | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       [ | ||||||
|  |         View( | ||||||
|  |           { | ||||||
|  |             style: { | ||||||
|  |               textAlign: "center", | ||||||
|  |             }, | ||||||
|  |           }, | ||||||
|  |           Text( | ||||||
|  |             { | ||||||
|  |               align: "center", | ||||||
|  |               paragraph: true, | ||||||
|  |               style: { | ||||||
|  |                 marginBottom: "10px", | ||||||
|  |                 color: "#fff", | ||||||
|  |                 fontSize: 23, | ||||||
|  |                 verticalAlign: "middle", | ||||||
|  |               }, | ||||||
|  |             }, | ||||||
|  |             "TOTPS:" | ||||||
|  |           ) | ||||||
|  |         ), | ||||||
|  |         ...totpEntrys, | ||||||
|  |         createButton | ||||||
|  |       ] | ||||||
|  |     ); | ||||||
|  |     return body; | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | function GetTOTPList(storage){ | ||||||
|  |   let totpEntrys = []; | ||||||
|  |   let counter = 0; | ||||||
|  |   storage.forEach((element) => { | ||||||
|  |     const elementId = counter; | ||||||
|  |     const textInput = TextInput({ | ||||||
|  |       placeholder: "otpauth://", | ||||||
|  |       label: "Change OTP link", | ||||||
|  |       onChange: (changes) => { | ||||||
|  |         try{ | ||||||
|  |         storage[elementId] = getTOTPByLink(changes) | ||||||
|  |         updateStorage(storage) | ||||||
|  |         } | ||||||
|  |         catch(err){ | ||||||
|  |           console.log(err) | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       labelStyle: { | ||||||
|  |         backgroundColor: "#14213D", | ||||||
|  |         textAlign: "center", | ||||||
|  |         display: "flex", | ||||||
|  |         alignItems: "center", | ||||||
|  |         justifyContent: "center", | ||||||
|  |         margin: "10px", | ||||||
|  |         flexGrow: 1, | ||||||
|  |         fontSize: "20px", | ||||||
|  |         color: "#E5E5E5", | ||||||
|  |         borderRadius: "5px" | ||||||
|  |       }, | ||||||
|  |     }); | ||||||
|  |     const textBig = Text( | ||||||
|  |       { | ||||||
|  |         align: "center", | ||||||
|  |         style: { | ||||||
|  |           color: "#ffffff", | ||||||
|  |           fontSize: "16px" | ||||||
|  |         }, | ||||||
|  |         paragraph: true, | ||||||
|  |       }, | ||||||
|  |       `${element.issuer}: ${element.client}` | ||||||
|  |     ); | ||||||
|  |     const delButton = Button( | ||||||
|  |       { | ||||||
|  |         onClick: () => { | ||||||
|  |           storage = storage.filter(x => storage.indexOf(x) != elementId) | ||||||
|  |           updateStorage(storage) | ||||||
|  |         }, | ||||||
|  |         style: { | ||||||
|  |           backgroundColor: "#ba181b", | ||||||
|  |           fontSize: "18px", | ||||||
|  |           color: "#ffffff", | ||||||
|  |           height: "fit-content", | ||||||
|  |           margin: "10px" | ||||||
|  |         }, | ||||||
|  |         label: "DEL" | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |     const text = Text( | ||||||
|  |       { | ||||||
|  |         style: { | ||||||
|  |           color: "#ffffff", | ||||||
|  |           fontSize: "14px" | ||||||
|  |         }, | ||||||
|  |         align: "center" | ||||||
|  |       }, | ||||||
|  |       `${element.hashType} | ${element.digits} digits | ${element.fetchTime} seconds | offset ${element.timeOffset} seconds` | ||||||
|  |     ); | ||||||
|  |     const view = View( | ||||||
|  |       { | ||||||
|  |         style: { | ||||||
|  |           textAlign: "center", | ||||||
|  |           border: "2px solid white", | ||||||
|  |           borderRadius: "5px", | ||||||
|  |           margin: "10px" | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       [textBig, text, View({style: { | ||||||
|  |         display: "grid", | ||||||
|  |         gridTemplateColumns: "1fr 100px" | ||||||
|  |       }}, [textInput, delButton])] | ||||||
|  |     ); | ||||||
|  |     totpEntrys.push({ text: text, view: view }); | ||||||
|  |     counter++; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   return totpEntrys.map(x => x.view); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function updateStorage(storage) { | function updateStorage(storage){ | ||||||
|     _props.settingsStorage.setItem("TOTPs", JSON.stringify(storage)); |   _props.settingsStorage.setItem('TOTPs', storage) | ||||||
| } | } | ||||||
| @ -3,43 +3,43 @@ import { TOTP } from "../../lib/totp-quickjs"; | |||||||
| const otpScheme = "otpauth:/"; | const otpScheme = "otpauth:/"; | ||||||
| 
 | 
 | ||||||
| export function getTOTPByLink(link) { | export function getTOTPByLink(link) { | ||||||
| 	try { |   try { | ||||||
| 		let args = link.split("/", otpScheme.length); |     let args = link.split("/", otpScheme.length); | ||||||
| 		let type = args[2]; //Returns 'hotp' or 'totp'
 |     let type = args[2]; //Returns 'hotp' or 'totp'
 | ||||||
| 		let issuer = args[3].split(":")[0]?.split("?")[0]; //Returns issuer
 |     let issuer = args[3].split(":")[0]?.split("?")[0]; //Returns issuer
 | ||||||
| 		let client = |     let client = | ||||||
| 			args[3].split(":")[1]?.split("?")[0] ?? |       args[3].split(":")[1]?.split("?")[0] ?? | ||||||
| 			args[3].split(":")[0]?.split("?")[0]; //Returns client
 |       args[3].split(":")[0]?.split("?")[0]; //Returns client
 | ||||||
| 		let secret = args[3].split("secret=")[1]?.split("&")[0]; //Returns secret
 |     let secret = args[3].split("secret=")[1]?.split("&")[0]; //Returns secret
 | ||||||
| 		let period = args[3].split("period=")[1]?.split("&")[0]; //Returns period
 |     let period = args[3].split("period=")[1]?.split("&")[0]; //Returns period
 | ||||||
| 		let digits = args[3].split("digits=")[1]?.split("&")[0]; //Returns digits
 |     let digits = args[3].split("digits=")[1]?.split("&")[0]; //Returns digits
 | ||||||
| 		let algorithm = args[3].split("algorithm=")[1]?.split("&")[0]; //Returns algorithm
 |     let algorithm = args[3].split("algorithm=")[1]?.split("&")[0]; //Returns algorithm
 | ||||||
| 
 | 
 | ||||||
| 		if (type.toLowerCase() != "totp") |     if (type.toLowerCase() != "totp") | ||||||
| 			throw new Error("Type is not valid, requires 'TOTP'"); |       throw new Error("Type is not valid, requires 'TOTP'"); | ||||||
| 
 | 
 | ||||||
| 		if (secret === undefined) throw new Error("Secret not defined"); |     if (secret === undefined) throw new Error("Secret not defined"); | ||||||
| 
 | 
 | ||||||
| 		issuer = issuer.replace("%20", " "); |     issuer = issuer.replace("%20", " "); | ||||||
| 		client = client.replace("%20", " "); |     client = client.replace("%20", " "); | ||||||
| 
 | 
 | ||||||
| 		return new TOTP( |     return new TOTP( | ||||||
| 			secret, |       secret, | ||||||
| 			issuer, |       issuer, | ||||||
| 			client, |       client, | ||||||
| 			digits, |       digits, | ||||||
| 			period, |       period, | ||||||
| 			0, |       0, | ||||||
| 			getHashType(algorithm) |       getHashType(algorithm) | ||||||
| 		); |     ); | ||||||
| 	} catch (err) { |   } catch (err) { | ||||||
| 		return null; |     return null; | ||||||
| 	} |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getHashType(algorithm) { | function getHashType(algorithm) { | ||||||
| 	if (algorithm == "SHA1") return "SHA-1"; |   if (algorithm == "SHA1") return "SHA-1"; | ||||||
| 	if (algorithm == "SHA256") return "SHA-256"; |   if (algorithm == "SHA256") return "SHA-256"; | ||||||
| 	if (algorithm == "SHA512") return "SHA-512"; |   if (algorithm == "SHA512") return "SHA-512"; | ||||||
| 	else return "SHA-1"; |   else return "SHA-1"; | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user