227 lines
7.2 KiB
JavaScript
227 lines
7.2 KiB
JavaScript
import { getTOTPByLink } from "./utils/queryParser.js";
|
||
|
||
let _props = null;
|
||
|
||
const colors = {
|
||
bg: "#101010",
|
||
linkBg: "#ffffffc0",
|
||
secondaryBg: "#282828",
|
||
text: "#fafafa",
|
||
alert: "#ad3c23",
|
||
notify: "#555555",
|
||
bigText: "#fafafa",
|
||
};
|
||
|
||
AppSettingsPage({
|
||
build(props) {
|
||
_props = props;
|
||
const storage = JSON.parse(
|
||
props.settingsStorage.getItem("TOTPs") ?? "[]",
|
||
);
|
||
const totpEntrys = GetTOTPList(storage);
|
||
const addTOTPsHint =
|
||
storage.length < 1
|
||
? Text(
|
||
{
|
||
paragraph: true,
|
||
align: "center",
|
||
style: {
|
||
paddingTop: "10px",
|
||
marginBottom: "10px",
|
||
color: colors.text,
|
||
fontSize: 16,
|
||
verticalAlign: "middle",
|
||
},
|
||
},
|
||
"For add a 2FA TOTP record you must have otpauth:// link or otpauth-migration:// link from Google Authenticator Migration QR-Code",
|
||
)
|
||
: null;
|
||
const createButton = TextInput({
|
||
placeholder: "otpauth(-migration)://",
|
||
label: "Add new TOTP record",
|
||
onChange: (changes) => {
|
||
let link = getTOTPByLink(changes);
|
||
if (link == null) {
|
||
console.log("link is invalid");
|
||
return;
|
||
}
|
||
|
||
if (Array.isArray(link)) storage.push(...link);
|
||
else storage.push(link);
|
||
|
||
updateStorage(storage);
|
||
},
|
||
labelStyle: {
|
||
backgroundColor: colors.notify,
|
||
display: "flex",
|
||
alignItems: "center",
|
||
justifyContent: "center",
|
||
margin: "10px",
|
||
fontSize: "20px",
|
||
color: colors.text,
|
||
borderRadius: "5px",
|
||
position: storage.length < 1 ? "absolute" : null, //TODO: Сделать что-то с этим кошмаром
|
||
bottom: storage.length < 1 ? "0px" : null,
|
||
left: storage.length < 1 ? "0px" : null,
|
||
right: storage.length < 1 ? "0px" : null,
|
||
},
|
||
});
|
||
|
||
var body = Section(
|
||
{
|
||
style: {
|
||
backgroundColor: colors.bg,
|
||
minHeight: "100vh",
|
||
},
|
||
},
|
||
[
|
||
View(
|
||
{
|
||
style: {
|
||
textAlign: "center",
|
||
},
|
||
},
|
||
storage.length < 1
|
||
? addTOTPsHint
|
||
: Text(
|
||
{
|
||
align: "center",
|
||
paragraph: true,
|
||
style: {
|
||
marginBottom: "10px",
|
||
color: colors.bigText,
|
||
fontSize: 23,
|
||
fontWeight: "500",
|
||
verticalAlign: "middle",
|
||
},
|
||
},
|
||
"TOTP records:",
|
||
),
|
||
),
|
||
...totpEntrys,
|
||
createButton,
|
||
View(
|
||
{
|
||
style: {
|
||
display: "flex",
|
||
justifyContent: "center",
|
||
},
|
||
},
|
||
Link(
|
||
{
|
||
source: "https://github.com/Lisoveliy/totpfit/blob/main/docs/guides/how-to-add-totps/README.md",
|
||
},
|
||
"Instruction | Report issue (GitHub)",
|
||
),
|
||
),
|
||
],
|
||
);
|
||
return body;
|
||
},
|
||
});
|
||
|
||
function GetTOTPList(storage) {
|
||
let totpEntrys = [];
|
||
let counter = 0;
|
||
storage.forEach((element) => {
|
||
const elementId = counter;
|
||
const textInput = TextInput({
|
||
placeholder: "otpauth(-migration)://",
|
||
label: "Change TOTP link",
|
||
onChange: (changes) => {
|
||
try {
|
||
let link = getTOTPByLink(changes);
|
||
if (Array.isArray(link)) return;
|
||
|
||
storage[elementId] = link;
|
||
updateStorage(storage);
|
||
} catch (err) {
|
||
console.log(err);
|
||
}
|
||
},
|
||
labelStyle: {
|
||
backgroundColor: colors.notify,
|
||
textAlign: "center",
|
||
display: "flex",
|
||
alignItems: "center",
|
||
justifyContent: "center",
|
||
margin: "10px",
|
||
flexGrow: 1,
|
||
fontSize: "20px",
|
||
color: colors.text,
|
||
borderRadius: "5px",
|
||
},
|
||
});
|
||
const textBig = Text(
|
||
{
|
||
align: "center",
|
||
style: {
|
||
color: colors.text,
|
||
fontSize: "18px",
|
||
fontWeight: "500",
|
||
},
|
||
paragraph: true,
|
||
},
|
||
`${element.issuer}: ${element.client}`,
|
||
);
|
||
const delButton = Button({
|
||
onClick: () => {
|
||
storage = storage.filter(
|
||
(x) => storage.indexOf(x) != elementId,
|
||
);
|
||
updateStorage(storage);
|
||
},
|
||
style: {
|
||
backgroundColor: colors.alert,
|
||
fontSize: "18px",
|
||
color: colors.text,
|
||
height: "fit-content",
|
||
margin: "10px",
|
||
},
|
||
label: "Delete",
|
||
});
|
||
const text = Text(
|
||
{
|
||
style: {
|
||
color: colors.text,
|
||
fontSize: "14px",
|
||
},
|
||
align: "center",
|
||
},
|
||
`${element.hashType} | ${element.digits} digits | ${element.fetchTime} seconds | ${element.timeOffset} sec offset`,
|
||
);
|
||
const view = View(
|
||
{
|
||
style: {
|
||
textAlign: "center",
|
||
backgroundColor: colors.secondaryBg,
|
||
//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) {
|
||
_props.settingsStorage.setItem("TOTPs", JSON.stringify(storage));
|
||
}
|