deepsite / auth.js
almortamoh's picture
Upload 36 files
a79063d verified
raw
history blame
14.7 kB
// نظام المصادقة والأمان
class AuthenticationManager {
constructor() {
this.currentUser = null;
this.sessionTimeout = 15 * 60 * 1000; // 15 دقيقة
this.maxLoginAttempts = 3;
this.lockoutDuration = 30 * 60 * 1000; // 30 دقيقة
this.biometricCredential = null;
this.init();
}
// تهيئة نظام المصادقة
init() {
this.setupSessionManagement();
this.loadStoredCredentials();
this.checkBiometricSupport();
}
// إعداد إدارة الجلسة
setupSessionManagement() {
// تحديث وقت النشاط عند التفاعل
document.addEventListener('click', () => this.updateLastActivity());
document.addEventListener('keypress', () => this.updateLastActivity());
document.addEventListener('touchstart', () => this.updateLastActivity());
// فحص انتهاء الجلسة كل دقيقة
setInterval(() => this.checkSessionExpiry(), 60000);
}
// تسجيل دخول بالرقم ورمز PIN
async loginWithPin(phoneNumber, pin) {
try {
// التحقق من محاولات تسجيل الدخول
if (this.isAccountLocked(phoneNumber)) {
const lockoutTime = this.getLockoutRemainingTime(phoneNumber);
throw new Error(`الحساب مقفل. المحاولة مرة أخرى خلال ${Math.ceil(lockoutTime / 60000)} دقيقة`);
}
// التحقق من صحة البيانات
if (!this.validatePhoneNumber(phoneNumber)) {
throw new Error('رقم الهاتف غير صحيح');
}
if (!this.validatePin(pin)) {
throw new Error('رمز PIN يجب أن يكون 4-6 أرقام');
}
// محاكاة التحقق من البيانات
const isValid = await this.verifyCredentials(phoneNumber, pin);
if (!isValid) {
this.recordFailedAttempt(phoneNumber);
const remainingAttempts = this.getRemainingAttempts(phoneNumber);
if (remainingAttempts <= 0) {
this.lockAccount(phoneNumber);
throw new Error('تم قفل الحساب بسبب المحاولات الخاطئة المتكررة');
}
throw new Error(`بيانات تسجيل الدخول غير صحيحة. المحاولات المتبقية: ${remainingAttempts}`);
}
// تسجيل دخول ناجح
this.clearFailedAttempts(phoneNumber);
const user = await this.createUserSession(phoneNumber, pin);
return user;
} catch (error) {
console.error('خطأ في تسجيل الدخول:', error);
throw error;
}
}
// تسجيل دخول بالبصمة
async loginWithBiometric() {
try {
if (!this.isBiometricSupported()) {
throw new Error('المصادقة البيومترية غير مدعومة في هذا المتصفح');
}
if (!this.biometricCredential) {
throw new Error('لم يتم تسجيل بصمة مسبقاً. يرجى تسجيل الدخول برمز PIN أولاً');
}
// التحقق من البصمة
const credential = await navigator.credentials.get({
publicKey: {
challenge: this.generateChallenge(),
allowCredentials: [{
type: 'public-key',
id: this.biometricCredential.id
}],
timeout: 60000,
userVerification: 'required'
}
});
if (!credential) {
throw new Error('فشل في التحقق من البصمة');
}
// إنشاء جلسة المستخدم
const savedUser = this.getStoredUser();
if (!savedUser) {
throw new Error('لم يتم العثور على بيانات المستخدم');
}
const user = await this.createUserSession(savedUser.phone, null, 'biometric');
return user;
} catch (error) {
console.error('خطأ في تسجيل الدخول بالبصمة:', error);
throw error;
}
}
// تسجيل البصمة
async registerBiometric(phoneNumber) {
try {
if (!this.isBiometricSupported()) {
throw new Error('المصادقة البيومترية غير مدعومة');
}
const credential = await navigator.credentials.create({
publicKey: {
challenge: this.generateChallenge(),
rp: {
name: 'محفظتي الموحدة',
id: window.location.hostname
},
user: {
id: new TextEncoder().encode(phoneNumber),
name: phoneNumber,
displayName: `مستخدم ${phoneNumber}`
},
pubKeyCredParams: [{
type: 'public-key',
alg: -7 // ES256
}],
timeout: 60000,
attestation: 'none',
authenticatorSelection: {
authenticatorAttachment: 'platform',
userVerification: 'required'
}
}
});
if (!credential) {
throw new Error('فشل في تسجيل البصمة');
}
// حفظ بيانات البصمة
this.biometricCredential = {
id: credential.rawId,
publicKey: credential.response.publicKey,
phoneNumber: phoneNumber,
registeredAt: new Date().toISOString()
};
this.storeBiometricCredential();
return true;
} catch (error) {
console.error('خطأ في تسجيل البصمة:', error);
throw error;
}
}
// إنشاء جلسة مستخدم
async createUserSession(phoneNumber, pin, authMethod = 'pin') {
const user = {
id: this.generateUserId(),
phone: phoneNumber,
name: this.extractNameFromPhone(phoneNumber),
authMethod: authMethod,
loginTime: new Date().toISOString(),
lastActivity: new Date().toISOString(),
sessionId: this.generateSessionId()
};
this.currentUser = user;
this.storeUserSession(user);
this.updateLastActivity();
return user;
}
// تسجيل الخروج
logout() {
this.currentUser = null;
this.clearUserSession();
this.clearStoredCredentials();
// إعادة توجيه لشاشة تسجيل الدخول
if (window.app) {
window.app.switchScreen('login');
}
}
// التحقق من صحة الجلسة
isSessionValid() {
if (!this.currentUser) {
return false;
}
const lastActivity = new Date(this.currentUser.lastActivity);
const now = new Date();
const timeDiff = now.getTime() - lastActivity.getTime();
return timeDiff < this.sessionTimeout;
}
// فحص انتهاء الجلسة
checkSessionExpiry() {
if (this.currentUser && !this.isSessionValid()) {
this.showSessionExpiredDialog();
}
}
// عرض حوار انتهاء الجلسة
showSessionExpiredDialog() {
if (confirm('انتهت صلاحية الجلسة. هل تريد تسجيل الدخول مرة أخرى؟')) {
this.logout();
} else {
this.logout();
}
}
// تحديث وقت النشاط الأخير
updateLastActivity() {
if (this.currentUser) {
this.currentUser.lastActivity = new Date().toISOString();
this.storeUserSession(this.currentUser);
}
}
// التحقق من قفل الحساب
isAccountLocked(phoneNumber) {
const lockData = this.getLockData(phoneNumber);
if (!lockData) return false;
const now = new Date().getTime();
return now < lockData.lockedUntil;
}
// الحصول على الوقت المتبقي للقفل
getLockoutRemainingTime(phoneNumber) {
const lockData = this.getLockData(phoneNumber);
if (!lockData) return 0;
const now = new Date().getTime();
return Math.max(0, lockData.lockedUntil - now);
}
// تسجيل محاولة فاشلة
recordFailedAttempt(phoneNumber) {
const attempts = this.getFailedAttempts(phoneNumber);
attempts.push(new Date().toISOString());
localStorage.setItem(`failed_attempts_${phoneNumber}`, JSON.stringify(attempts));
}
// الحصول على المحاولات الفاشلة
getFailedAttempts(phoneNumber) {
const stored = localStorage.getItem(`failed_attempts_${phoneNumber}`);
return stored ? JSON.parse(stored) : [];
}
// الحصول على المحاولات المتبقية
getRemainingAttempts(phoneNumber) {
const attempts = this.getFailedAttempts(phoneNumber);
return Math.max(0, this.maxLoginAttempts - attempts.length);
}
// قفل الحساب
lockAccount(phoneNumber) {
const lockData = {
lockedAt: new Date().toISOString(),
lockedUntil: new Date().getTime() + this.lockoutDuration
};
localStorage.setItem(`account_lock_${phoneNumber}`, JSON.stringify(lockData));
}
// الحصول على بيانات القفل
getLockData(phoneNumber) {
const stored = localStorage.getItem(`account_lock_${phoneNumber}`);
return stored ? JSON.parse(stored) : null;
}
// مسح المحاولات الفاشلة
clearFailedAttempts(phoneNumber) {
localStorage.removeItem(`failed_attempts_${phoneNumber}`);
localStorage.removeItem(`account_lock_${phoneNumber}`);
}
// التحقق من صحة رقم الهاتف
validatePhoneNumber(phoneNumber) {
return /^7[0-9]{8}$/.test(phoneNumber);
}
// التحقق من صحة رمز PIN
validatePin(pin) {
return /^[0-9]{4,6}$/.test(pin);
}
// محاكاة التحقق من البيانات
async verifyCredentials(phoneNumber, pin) {
// محاكاة استدعاء API
await new Promise(resolve => setTimeout(resolve, 1000));
// في التطبيق الحقيقي، سيتم التحقق من البيانات مع الخادم
// للتجربة، نقبل أي رقم هاتف صحيح ورمز PIN من 4-6 أرقام
return this.validatePhoneNumber(phoneNumber) && this.validatePin(pin);
}
// فحص دعم المصادقة البيومترية
isBiometricSupported() {
return window.PublicKeyCredential &&
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable;
}
// فحص دعم المصادقة البيومترية
async checkBiometricSupport() {
if (this.isBiometricSupported()) {
try {
const available = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
return available;
} catch (error) {
console.warn('خطأ في فحص دعم المصادقة البيومترية:', error);
return false;
}
}
return false;
}
// توليد تحدي للمصادقة البيومترية
generateChallenge() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return array;
}
// توليد معرف مستخدم
generateUserId() {
return 'user_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
}
// توليد معرف جلسة
generateSessionId() {
return 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
}
// استخراج اسم من رقم الهاتف
extractNameFromPhone(phoneNumber) {
return `مستخدم ${phoneNumber.substr(-4)}`;
}
// حفظ جلسة المستخدم
storeUserSession(user) {
localStorage.setItem('unifiedWallet_session', JSON.stringify(user));
}
// تحميل جلسة المستخدم
loadStoredSession() {
const stored = localStorage.getItem('unifiedWallet_session');
if (stored) {
const user = JSON.parse(stored);
if (this.isSessionValid()) {
this.currentUser = user;
return user;
} else {
this.clearUserSession();
}
}
return null;
}
// مسح جلسة المستخدم
clearUserSession() {
localStorage.removeItem('unifiedWallet_session');
}
// حفظ بيانات البصمة
storeBiometricCredential() {
if (this.biometricCredential) {
localStorage.setItem('unifiedWallet_biometric', JSON.stringify(this.biometricCredential));
}
}
// تحميل بيانات البصمة
loadStoredCredentials() {
const stored = localStorage.getItem('unifiedWallet_biometric');
if (stored) {
this.biometricCredential = JSON.parse(stored);
}
}
// مسح بيانات البصمة
clearStoredCredentials() {
localStorage.removeItem('unifiedWallet_biometric');
this.biometricCredential = null;
}
// الحصول على المستخدم المحفوظ
getStoredUser() {
const stored = localStorage.getItem('unifiedWallet_user');
return stored ? JSON.parse(stored) : null;
}
// الحصول على المستخدم الحالي
getCurrentUser() {
return this.currentUser;
}
// التحقق من تسجيل الدخول
isLoggedIn() {
return this.currentUser !== null && this.isSessionValid();
}
}
// تصدير الكلاس للاستخدام في التطبيق الرئيسي
window.AuthenticationManager = AuthenticationManager;