From 259c2cdd2e4db8cd2e995f6802479da87526af5a Mon Sep 17 00:00:00 2001 From: Savely Savenok Date: Fri, 8 Aug 2025 15:34:34 +0300 Subject: [PATCH] feat: added sort for totps, added possibility to change issuer and client name --- .prettierrc.yaml | 2 +- lib/totp-quickjs/index.js | 9 ++++- setting/consts.js | 40 ++++++++++++++++++++ setting/index.js | 72 ++++++++++++++++-------------------- setting/ui/card.js | 78 +++++++++++++++++++++++++++++++-------- 5 files changed, 142 insertions(+), 59 deletions(-) create mode 100644 setting/consts.js diff --git a/.prettierrc.yaml b/.prettierrc.yaml index 68ea04d..f1d7f90 100644 --- a/.prettierrc.yaml +++ b/.prettierrc.yaml @@ -1 +1 @@ -tabWidth: 4 \ No newline at end of file +tabWidth: 4 diff --git a/lib/totp-quickjs/index.js b/lib/totp-quickjs/index.js index 2d6c6e5..eaef65e 100644 --- a/lib/totp-quickjs/index.js +++ b/lib/totp-quickjs/index.js @@ -48,12 +48,17 @@ export class TOTP { */ getOTP(time = Date.now()) { const unixTime = (time / 1000 + this.timeOffset) / this.fetchTime; - const otp = getHOTP(Math.floor(unixTime), this.secret, this.digits, this.hashType); + const otp = getHOTP( + Math.floor(unixTime), + this.secret, + this.digits, + this.hashType, + ); const expireTime = time + (this.fetchTime - ((time / 1000 + this.timeOffset) % this.fetchTime)) * - 1000; + 1000; const createdTime = time - ((time / 1000 + this.timeOffset) % this.fetchTime) * 1000; diff --git a/setting/consts.js b/setting/consts.js new file mode 100644 index 0000000..6e73477 --- /dev/null +++ b/setting/consts.js @@ -0,0 +1,40 @@ +export const colors = { + bg: "#101010", + linkBg: "#ffffffc0", + secondaryBg: "#282828", + text: "#fafafa", + alert: "#ad3c23", + notify: "#555555", + bigText: "#fafafa", +}; + +export const content = { + addTotpsHint: + "For add a 2FA TOTP record you must have otpauth:// link or otpauth-migration:// link from Google Authenticator Migration QR-Code", + totpRecordsHint: "TOTP records:", + createButton: { + placeHolder: "otpauth(-migration)://", + label: "Add new TOTP record", + }, + instructionLink: { + label: "Instruction | Report issue (GitHub)", + source: "https://github.com/Lisoveliy/totpfit/blob/main/docs/guides/how-to-add-totps/README.md", + }, + changeButton: { + label: "Change TOTP link", + placeHolder: "otpauth(-migration)://", + }, + deleteButton: { + label: "Delete", + }, + totpLabelText: { + eval(issuer, client) { + return `${issuer}: ${client}`; + }, + }, + totpDescText: { + eval(hashType, digits, fetchTime, timeOffset) { + return `${hashType} | ${digits} digits | ${fetchTime} seconds | ${timeOffset} sec offset`; + }, + }, +}; diff --git a/setting/index.js b/setting/index.js index d4b5d72..413acc6 100644 --- a/setting/index.js +++ b/setting/index.js @@ -1,5 +1,6 @@ import { getTOTPByLink } from "./utils/queryParser.js"; import { createTOTPCard } from "./ui/card.js"; +import { colors, content } from "./consts.js"; let _props = null; let editingIndex = -1; @@ -7,16 +8,6 @@ let tempIssuer = ""; let tempClient = ""; let errorMessage = ""; -const colors = { - bg: "#101010", - linkBg: "#ffffffc0", - secondaryBg: "#282828", - text: "#fafafa", - alert: "#ad3c23", - notify: "#555555", - bigText: "#fafafa", -}; - function updateStorage(storage) { _props.settingsStorage.setItem("TOTPs", JSON.stringify(storage)); } @@ -95,20 +86,20 @@ AppSettingsPage({ verticalAlign: "middle", }, }, - "For add a 2FA TOTP record you must have otpauth:// link or otpauth-migration:// link from Google Authenticator Migration QR-Code", + content.addTotpsHint, ) : null; const createButton = TextInput({ - placeholder: "otpauth(-migration)://", - label: "Add new TOTP record", + placeholder: content.createButton.placeHolder, + label: content.createButton.label, onChange: (changes) => { try { errorMessage = ""; let link = getTOTPByLink(changes); if (link == null) { throw new Error( - "Unsupported link type. Please use an otpauth:// or otpauth-migration:// link.", + "Unsupported link type. Please use an otpauth:// or otpauth-migration:// link", ); } @@ -132,7 +123,6 @@ AppSettingsPage({ fontSize: "20px", color: colors.text, borderRadius: "5px", - width: "100%", height: "45px", }, }); @@ -143,7 +133,6 @@ AppSettingsPage({ style: { color: colors.alert, textAlign: "center", - margin: "5px", }, }, errorMessage, @@ -153,11 +142,29 @@ AppSettingsPage({ const bottomContainer = View( { style: { - padding: "5px 0px", backgroundColor: colors.bg, }, }, - [errorText, createButton].filter(Boolean), + [ + View( + { + style: { + display: "flex", + justifyContent: "center", + marginTop: "20px", + marginBottom: "20px", + }, + }, + Link( + { + source: content.instructionLink.source, + }, + content.instructionLink.label, + ), + ), + errorText, + createButton, + ].filter(Boolean), ); const pageContainer = View( @@ -185,6 +192,7 @@ AppSettingsPage({ align: "center", paragraph: true, style: { + marginTop: "10px", marginBottom: "10px", color: colors.bigText, fontSize: 23, @@ -192,7 +200,7 @@ AppSettingsPage({ verticalAlign: "middle", }, }, - "TOTP records:", + content.totpRecordsHint, ), ], ), @@ -200,29 +208,13 @@ AppSettingsPage({ View( { style: { - flexGrow: 1, - overflow: "scroll", + height: "100%", + overflowX: "hidden", + overflowY: "auto", + backgroundColor: colors.bg, }, }, - [ - ...totpEntrys, - View( - { - style: { - display: "flex", - justifyContent: "center", - marginTop: "20px", - marginBottom: "20px", - }, - }, - Link( - { - source: "https://github.com/Lisoveliy/totpfit/blob/main/docs/guides/how-to-add-totps/README.md", - }, - "Instruction | Report issue (GitHub)", - ), - ), - ], + [...totpEntrys], ), bottomContainer, diff --git a/setting/ui/card.js b/setting/ui/card.js index 7c04771..f9f058f 100644 --- a/setting/ui/card.js +++ b/setting/ui/card.js @@ -1,3 +1,5 @@ +import { colors, content } from "../consts"; + export function createTOTPCard({ element, index, @@ -13,13 +15,6 @@ export function createTOTPCard({ onIssuerChange, onClientChange, }) { - const colors = { - secondaryBg: "#282828", - text: "#fafafa", - alert: "#ad3c23", - notify: "#555555", - }; - const infoView = View( { style: { @@ -31,23 +26,59 @@ export function createTOTPCard({ isEditing ? [ TextInput({ - label: "Issuer", + label: "Rename Issuer", value: tempIssuer, onChange: onIssuerChange, + labelStyle: { + backgroundColor: colors.notify, + display: "flex", + alignItems: "center", + justifyContent: "center", + margin: "10px", + fontSize: "20px", + color: colors.text, + borderRadius: "5px", + height: "40px", + width: "200px" + }, + subStyle: { + display: "none", + }, }), TextInput({ - label: "Client", + label: "Rename client", value: tempClient, onChange: onClientChange, + labelStyle: { + backgroundColor: colors.notify, + display: "flex", + alignItems: "center", + justifyContent: "center", + margin: "10px", + fontSize: "20px", + color: colors.text, + borderRadius: "5px", + height: "40px", + width: "200px" + }, + subStyle: { + display: "none", + }, }), ] : [ Text( - { style: { color: colors.text, marginBottom: "2px" } }, + { + style: { + color: colors.text, + marginBottom: "2px", + fontWeight: "600", + }, + }, `Issuer: ${element.issuer}`, ), Text( - { style: { color: colors.text } }, + { style: { color: colors.text, fontWeight: "600" } }, `Client: ${element.client}`, ), ], @@ -93,15 +124,25 @@ export function createTOTPCard({ { style: { display: "flex", flexDirection: "column" } }, [ Button({ - label: "↑", + label: "⬆", disabled: index === 0, - style: { width: "50px", margin: "2px" }, + style: { + width: "50px", + margin: "2px", + color: colors.text, + backgroundColor: colors.notify, + }, onClick: onMoveUp, }), Button({ - label: "↓", + label: "⬇", disabled: index === storage.length - 1, - style: { width: "50px", margin: "2px" }, + style: { + width: "50px", + margin: "2px", + color: colors.text, + backgroundColor: colors.notify, + }, onClick: onMoveDown, }), ], @@ -117,7 +158,12 @@ export function createTOTPCard({ marginTop: "5px", }, }, - `${element.hashType} | ${element.digits} digits | ${element.fetchTime} seconds | ${element.timeOffset} sec offset`, + content.totpDescText.eval( + element.hashType, + element.digits, + element.fetchTime, + element.timeOffset, + ), ), buttonsView, ]);