refactor: simplify auth and subscription links

This commit is contained in:
2026-07-28 10:32:21 +08:00
parent b7a7cd9c71
commit fc8c23beee
41 changed files with 739 additions and 1468 deletions
+28 -26
View File
@@ -1,51 +1,55 @@
/**
* Token management — the page MUST be opened with ?token=xxx
* The token is validated against the backend /api/env endpoint.
* If invalid or missing, the router guard shows a 404 page.
* Login storage for remote Sub-Store backend URI + admin token.
*/
const REMOTE_URI_KEY = 'sub_store_remote_uri'
const TOKEN_KEY = 'sub_store_admin_token'
const VALIDATED_KEY = 'sub_store_token_validated'
/** Extract token from URL query string */
export function getTokenFromURL() {
const params = new URLSearchParams(window.location.search)
return params.get('token') || ''
export function normalizeRemoteUri(uri) {
const value = (uri || '').trim().replace(/\/+$/, '').replace(/\/api$/, '')
if (!value) return ''
const parsed = new URL(value)
if (!['http:', 'https:'].includes(parsed.protocol)) {
throw new Error('Remote URI must use http or https')
}
return parsed.toString().replace(/\/+$/, '')
}
/** Store token in localStorage (persists across page reloads) */
export function storeToken(token) {
if (token) {
export function storeLogin(remoteUri, token) {
const normalizedRemoteUri = normalizeRemoteUri(remoteUri)
if (normalizedRemoteUri && token) {
localStorage.setItem(REMOTE_URI_KEY, normalizedRemoteUri)
localStorage.setItem(TOKEN_KEY, token)
localStorage.setItem(VALIDATED_KEY, 'true')
}
}
/** Get stored token */
export function getStoredRemoteUri() {
return localStorage.getItem(REMOTE_URI_KEY) || ''
}
export function getStoredToken() {
return localStorage.getItem(TOKEN_KEY) || ''
}
/** Check if token has been validated */
export function isTokenValidated() {
return localStorage.getItem(VALIDATED_KEY) === 'true'
}
/** Clear token (logout) */
export function clearToken() {
localStorage.removeItem(REMOTE_URI_KEY)
localStorage.removeItem(TOKEN_KEY)
localStorage.removeItem(VALIDATED_KEY)
}
/**
* Validate token against backend by calling /api/env.
* Returns true if token is valid, false otherwise.
*/
export async function validateToken(token) {
export async function validateToken(token, remoteUri) {
if (!token) return false
try {
const base = (window.SUB_STORE_CONFIG?.apiBaseUrl) || ''
const resp = await fetch(`${base}/api/env?token=${encodeURIComponent(token)}`)
const base = normalizeRemoteUri(remoteUri)
const resp = await fetch(`${base}/api/env`, {
headers: { Authorization: `Bearer ${token}` },
})
if (!resp.ok) return false
const data = await resp.json()
return data.status === 'success'
@@ -54,12 +58,10 @@ export async function validateToken(token) {
}
}
/**
* Get the effective token: from URL if present, otherwise from storage.
* This is used by the API layer to always send the token.
*/
export function getEffectiveToken() {
const urlToken = getTokenFromURL()
if (urlToken) return urlToken
return getStoredToken()
}
export function getApiBaseUrl() {
return getStoredRemoteUri() || (window.SUB_STORE_CONFIG?.apiBaseUrl) || ''
}