This commit is contained in:
eoao
2025-04-26 17:24:39 +08:00
commit 24ba4772e6
107 changed files with 13612 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
const encoder = new TextEncoder();
const saltHashUtils = {
generateSalt(length = 16) {
const array = new Uint8Array(length);
crypto.getRandomValues(array);
return btoa(String.fromCharCode(...array));
},
async hashPassword(password) {
const salt = this.generateSalt();
const hash = await this.genHashPassword(password, salt);
return { salt, hash };
},
async genHashPassword(password, salt) {
const data = encoder.encode(salt + password);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return btoa(String.fromCharCode(...hashArray));
},
async verifyPassword(inputPassword, salt, storedHash) {
const hash = await this.genHashPassword(inputPassword, salt);
return hash === storedHash;
}
};
export default saltHashUtils;

View File

@@ -0,0 +1,9 @@
const emailUtils = {
getDomain(email) {
if (typeof email !== 'string') return ''
const parts = email.split('@')
return parts.length === 2 ? parts[1] : ''
}
}
export default emailUtils

View File

@@ -0,0 +1,9 @@
const fileUtils = {
getExtFileName(filename) {
const index = filename.lastIndexOf('.');
return index !== -1 ? filename.slice(index) : '';
}
};
export default fileUtils

View File

@@ -0,0 +1,87 @@
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const base64url = (input) => {
const str = btoa(String.fromCharCode(...new Uint8Array(input)));
return str.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
};
const base64urlDecode = (str) => {
str = str.replace(/-/g, '+').replace(/_/g, '/');
while (str.length % 4) str += '=';
return Uint8Array.from(atob(str), c => c.charCodeAt(0));
};
const jwtUtils = {
async generateToken(c, payload, expiresInSeconds) {
const header = {
alg: 'HS256',
typ: 'JWT'
};
const now = Math.floor(Date.now() / 1000);
const exp = expiresInSeconds ? now + expiresInSeconds : undefined;
const fullPayload = {
...payload,
iat: now,
...(exp ? { exp } : {})
};
const headerStr = base64url(encoder.encode(JSON.stringify(header)));
const payloadStr = base64url(encoder.encode(JSON.stringify(fullPayload)));
const data = `${headerStr}.${payloadStr}`;
const key = await crypto.subtle.importKey(
'raw',
encoder.encode(c.env.jwt_secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));
const signatureStr = base64url(signature);
return `${data}.${signatureStr}`;
},
async verifyToken(c, token) {
try {
const [headerB64, payloadB64, signatureB64] = token.split('.');
if (!headerB64 || !payloadB64 || !signatureB64) return null;
const data = `${headerB64}.${payloadB64}`;
const key = await crypto.subtle.importKey(
'raw',
encoder.encode(c.env.jwt_secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['verify']
);
const valid = await crypto.subtle.verify(
'HMAC',
key,
base64urlDecode(signatureB64),
encoder.encode(data)
);
if (!valid) return null;
const payloadJson = decoder.decode(base64urlDecode(payloadB64));
const payload = JSON.parse(payloadJson);
const now = Math.floor(Date.now() / 1000);
if (payload.exp && payload.exp < now) return null;
return payload;
} catch (err) {
return null;
}
}
};
export default jwtUtils;

View File

@@ -0,0 +1,7 @@
const verifyUtils = {
isEmail(str) {
return /^[a-zA-Z0-9]+@([a-zA-Z0-9-]+\.)+[a-zA-Z0-9-]+$/.test(str);
}
}
export default verifyUtils