保存
This commit is contained in:
31
mail-worker/src/utils/crypto-utils.js
Normal file
31
mail-worker/src/utils/crypto-utils.js
Normal 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;
|
||||
9
mail-worker/src/utils/email-utils.js
Normal file
9
mail-worker/src/utils/email-utils.js
Normal 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
|
||||
9
mail-worker/src/utils/file-utils.js
Normal file
9
mail-worker/src/utils/file-utils.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const fileUtils = {
|
||||
getExtFileName(filename) {
|
||||
const index = filename.lastIndexOf('.');
|
||||
return index !== -1 ? filename.slice(index) : '';
|
||||
}
|
||||
};
|
||||
|
||||
export default fileUtils
|
||||
|
||||
87
mail-worker/src/utils/jwt-utils.js
Normal file
87
mail-worker/src/utils/jwt-utils.js
Normal 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;
|
||||
7
mail-worker/src/utils/verify-utils.js
Normal file
7
mail-worker/src/utils/verify-utils.js
Normal 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
|
||||
Reference in New Issue
Block a user