mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-12-20 06:13:24 +00:00
React
This commit is contained in:
89
frontend/src/modules/AuthStore.ts
Normal file
89
frontend/src/modules/AuthStore.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { getUnixTime, parseISO } from "date-fns";
|
||||
import type { TokenResponse } from "src/api/backend";
|
||||
|
||||
export const TOKEN_KEY = "authentications";
|
||||
|
||||
export class AuthStore {
|
||||
// Get all tokens from stack
|
||||
get tokens() {
|
||||
const t = localStorage.getItem(TOKEN_KEY);
|
||||
let tokens = [];
|
||||
if (t !== null) {
|
||||
try {
|
||||
tokens = JSON.parse(t);
|
||||
} catch (e) {
|
||||
console.error("Failed to parse tokens from localStorage", e);
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
// Get last token from stack
|
||||
get token() {
|
||||
const t = this.tokens;
|
||||
if (t.length) {
|
||||
return t[t.length - 1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get expires from last token
|
||||
get expires() {
|
||||
const t = this.token;
|
||||
if (t && typeof t.expires !== "undefined") {
|
||||
const expires = Number(t.expires);
|
||||
if (expires && !Number.isNaN(expires)) {
|
||||
return expires;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Filter out invalid tokens and return true if we find one that is valid
|
||||
// hasActiveToken() {
|
||||
// const t = this.tokens;
|
||||
// return t.length > 0;
|
||||
// }
|
||||
hasActiveToken() {
|
||||
const t = this.tokens;
|
||||
if (!t.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const now = Math.round(Date.now() / 1000);
|
||||
const oneMinuteBuffer = 60;
|
||||
for (let i = t.length - 1; i >= 0; i--) {
|
||||
const dte = getUnixTime(parseISO(t[i].expires));
|
||||
const valid = dte - oneMinuteBuffer > now;
|
||||
if (valid) {
|
||||
return true;
|
||||
}
|
||||
this.drop();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set a single token on the stack
|
||||
set({ token, expires }: TokenResponse) {
|
||||
localStorage.setItem(TOKEN_KEY, JSON.stringify([{ token, expires }]));
|
||||
}
|
||||
|
||||
// Add a token to the stack
|
||||
add({ token, expires }: TokenResponse) {
|
||||
const t = this.tokens;
|
||||
t.push({ token, expires });
|
||||
localStorage.setItem(TOKEN_KEY, JSON.stringify(t));
|
||||
}
|
||||
|
||||
// Drop a token from the stack
|
||||
drop() {
|
||||
const t = this.tokens;
|
||||
localStorage.setItem(TOKEN_KEY, JSON.stringify(t.splice(-1, 1)));
|
||||
}
|
||||
|
||||
clear() {
|
||||
localStorage.removeItem(TOKEN_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
export default new AuthStore();
|
||||
51
frontend/src/modules/Validations.tsx
Normal file
51
frontend/src/modules/Validations.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
const validateString = (minLength = 0, maxLength = 0) => {
|
||||
if (minLength <= 0 && maxLength <= 0) {
|
||||
// this doesn't require translation
|
||||
console.error("validateString() must be called with a min or max or both values in order to work!");
|
||||
}
|
||||
|
||||
return (value: string): string | undefined => {
|
||||
if (minLength && (typeof value === "undefined" || !value.length)) {
|
||||
return "This is required";
|
||||
}
|
||||
if (minLength && value.length < minLength) {
|
||||
return `Minimum length is ${minLength} character${minLength === 1 ? "" : "s"}`;
|
||||
}
|
||||
if (maxLength && (typeof value === "undefined" || value.length > maxLength)) {
|
||||
return `Maximum length is ${maxLength} character${maxLength === 1 ? "" : "s"}`;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const validateNumber = (min = -1, max = -1) => {
|
||||
if (min === -1 && max === -1) {
|
||||
// this doesn't require translation
|
||||
console.error("validateNumber() must be called with a min or max or both values in order to work!");
|
||||
}
|
||||
|
||||
return (value: string): string | undefined => {
|
||||
const int: number = +value;
|
||||
if (min > -1 && !int) {
|
||||
return "This is required";
|
||||
}
|
||||
if (min > -1 && int < min) {
|
||||
return `Minimum is ${min}`;
|
||||
}
|
||||
if (max > -1 && int > max) {
|
||||
return `Maximum is ${max}`;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const validateEmail = () => {
|
||||
return (value: string): string | undefined => {
|
||||
if (!value.length) {
|
||||
return "This is required";
|
||||
}
|
||||
if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(value)) {
|
||||
return "Invalid email address";
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export { validateEmail, validateNumber, validateString };
|
||||
Reference in New Issue
Block a user