ci: fix pipeline, update readme and anonymize ZT references
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
// Helper functions for password toggles and validation shared between login, setup, and overlay
|
||||
window.AuthHelpers = {
|
||||
/**
|
||||
* Initializes password visibility toggles.
|
||||
* @param {HTMLElement} rootEl
|
||||
*/
|
||||
initPasswordToggles(rootEl = document) {
|
||||
rootEl.querySelectorAll('.toggle-password').forEach(btn => {
|
||||
if (btn.dataset.initialized) return;
|
||||
btn.dataset.initialized = 'true';
|
||||
|
||||
btn.addEventListener('click', () => {
|
||||
const input = btn.parentElement.querySelector('input');
|
||||
if (!input) return;
|
||||
|
||||
const isPassword = input.type === 'password';
|
||||
input.type = isPassword ? 'text' : 'password';
|
||||
|
||||
btn.innerHTML = isPassword
|
||||
? '<i data-lucide="eye-off" class="eye-icon"></i>'
|
||||
: '<i data-lucide="eye" class="eye-icon"></i>';
|
||||
|
||||
if (typeof lucide !== 'undefined') {
|
||||
lucide.createIcons({ root: btn });
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Performs client-side password validation against complexity rules.
|
||||
* @param {string} val
|
||||
* @param {string} confirmVal
|
||||
* @returns {Object}
|
||||
*/
|
||||
validateComplexity(val, confirmVal) {
|
||||
const hasLength = val.length >= 8;
|
||||
const hasUpper = /[A-Z]/.test(val);
|
||||
const hasNumber = /[0-9]/.test(val);
|
||||
const hasSpecial = /[^a-zA-Z0-9]/.test(val);
|
||||
const matches = val === confirmVal && val.length > 0;
|
||||
|
||||
return {
|
||||
hasLength,
|
||||
hasUpper,
|
||||
hasNumber,
|
||||
hasSpecial,
|
||||
matches,
|
||||
allValid: hasLength && hasUpper && hasNumber && hasSpecial && matches
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates requirements list checklist UI.
|
||||
* @param {HTMLElement} rootEl
|
||||
* @param {Object} statuses
|
||||
*/
|
||||
updateRequirementsUI(rootEl, statuses) {
|
||||
const updateReq = (id, isValid) => {
|
||||
const li = rootEl.querySelector(`#${id}`);
|
||||
if (!li) return;
|
||||
li.className = isValid ? 'valid' : 'invalid';
|
||||
|
||||
const holder = li.querySelector('.icon-holder');
|
||||
if (holder) {
|
||||
holder.innerHTML = isValid
|
||||
? '<i data-lucide="check" style="width:14px;height:14px;"></i>'
|
||||
: '<i data-lucide="x" style="width:14px;height:14px;"></i>';
|
||||
if (typeof lucide !== 'undefined') {
|
||||
lucide.createIcons({ root: holder });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
updateReq('req-length', statuses.hasLength);
|
||||
updateReq('req-upper', statuses.hasUpper);
|
||||
updateReq('req-number', statuses.hasNumber);
|
||||
updateReq('req-special', statuses.hasSpecial);
|
||||
updateReq('req-match', statuses.matches);
|
||||
}
|
||||
};
|
||||
+1733
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 620 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 620 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
Vendored
+12
File diff suppressed because one or more lines are too long
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "Hydr'Hacked",
|
||||
"short_name": "Hydr'Hacked",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"orientation": "portrait",
|
||||
"background_color": "#1a1a1a",
|
||||
"theme_color": "#1a1a1a",
|
||||
"icons": [
|
||||
{
|
||||
"src": "images/icone-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "images/icone-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
+1173
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
||||
const CACHE_NAME = 'hydrhacked-v4.8';
|
||||
const STATIC_ASSETS = [
|
||||
'/style.css',
|
||||
'/app.auth.js',
|
||||
'/app.js',
|
||||
'/manifest.json',
|
||||
'/images/icone-192.png',
|
||||
'/images/icone-512.png',
|
||||
'/images/logo_transparent.png',
|
||||
'/lucide.min.js'
|
||||
];
|
||||
|
||||
// 1. INSTALLATION
|
||||
self.addEventListener('install', event => {
|
||||
self.skipWaiting();
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_NAME).then(cache => {
|
||||
console.log('[SW] Mise en cache des fichiers statiques');
|
||||
return cache.addAll(STATIC_ASSETS);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(
|
||||
caches.keys().then(cacheNames => {
|
||||
return Promise.all(
|
||||
cacheNames.map(cache => {
|
||||
if (cache !== CACHE_NAME) {
|
||||
console.log('[SW] Suppression ancien cache:', cache);
|
||||
return caches.delete(cache);
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
return self.clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', event => {
|
||||
const url = new URL(event.request.url);
|
||||
|
||||
const isStaticAsset = url.pathname.endsWith('.css') ||
|
||||
url.pathname.endsWith('.js') ||
|
||||
url.pathname.endsWith('.png') ||
|
||||
url.pathname.endsWith('.json');
|
||||
|
||||
if (!isStaticAsset || event.request.method !== 'GET') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stratégie Network-First : on tente le réseau, et on met à jour le cache. Sinon, fallback sur le cache.
|
||||
event.respondWith(
|
||||
fetch(event.request)
|
||||
.then(response => {
|
||||
if (response && response.status === 200) {
|
||||
const responseCopy = response.clone();
|
||||
caches.open(CACHE_NAME).then(cache => {
|
||||
cache.put(event.request, responseCopy);
|
||||
});
|
||||
}
|
||||
return response;
|
||||
})
|
||||
.catch(() => {
|
||||
return caches.match(event.request);
|
||||
})
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user