200 lines
5.5 KiB
JavaScript
200 lines
5.5 KiB
JavaScript
/**
|
|
* MobileApp Shared Authentication Module
|
|
*
|
|
* Provides authentication utilities for all mobile PWAs:
|
|
* - checkAuth() - Check if user is authenticated
|
|
* - login() - Authenticate user
|
|
* - logout() - Clear session
|
|
* - api - Generic API helper
|
|
*/
|
|
|
|
// Base API path for all MobileApp endpoints
|
|
const API_BASE = '/MobileApp';
|
|
|
|
// Shared auth state (can be imported by components)
|
|
export const authState = {
|
|
user: null,
|
|
isAuthenticated: false
|
|
};
|
|
|
|
/**
|
|
* Check if user is currently authenticated
|
|
* @returns {Promise<{authenticated: boolean, user?: object}>}
|
|
*/
|
|
export async function checkAuth() {
|
|
try {
|
|
const res = await fetch(`${API_BASE}/auth/check`, {
|
|
credentials: 'same-origin'
|
|
});
|
|
const data = await res.json();
|
|
|
|
authState.isAuthenticated = data.authenticated;
|
|
authState.user = data.user || null;
|
|
|
|
return data;
|
|
} catch (e) {
|
|
console.error('Auth check failed:', e);
|
|
authState.isAuthenticated = false;
|
|
authState.user = null;
|
|
return { authenticated: false };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Authenticate user with credentials
|
|
* @param {object} credentials - { username, password, rememberMe }
|
|
* @returns {Promise<{success: boolean, user?: object, message?: string}>}
|
|
*/
|
|
export async function login({ username, password, rememberMe = true }) {
|
|
try {
|
|
const res = await fetch(`${API_BASE}/auth/login`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'same-origin',
|
|
body: JSON.stringify({ username, password, rememberMe })
|
|
});
|
|
|
|
const data = await res.json();
|
|
|
|
if (data.success) {
|
|
authState.isAuthenticated = true;
|
|
authState.user = data.user;
|
|
}
|
|
|
|
return data;
|
|
} catch (e) {
|
|
console.error('Login failed:', e);
|
|
return { success: false, message: 'Netzwerkfehler' };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verify 2FA code
|
|
* @param {string} code - 5-digit verification code
|
|
* @returns {Promise<{success: boolean, user?: object, message?: string}>}
|
|
*/
|
|
export async function verify2FA(code) {
|
|
try {
|
|
const res = await fetch(`${API_BASE}/auth/verify2fa`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'same-origin',
|
|
body: JSON.stringify({ code })
|
|
});
|
|
|
|
const data = await res.json();
|
|
|
|
if (data.success) {
|
|
authState.isAuthenticated = true;
|
|
authState.user = data.user;
|
|
}
|
|
|
|
return data;
|
|
} catch (e) {
|
|
console.error('2FA verification failed:', e);
|
|
return { success: false, message: 'Netzwerkfehler' };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resend 2FA code
|
|
* @returns {Promise<{success: boolean, message?: string}>}
|
|
*/
|
|
export async function resend2FA() {
|
|
try {
|
|
const res = await fetch(`${API_BASE}/auth/resend2fa`, {
|
|
method: 'POST',
|
|
credentials: 'same-origin'
|
|
});
|
|
|
|
return await res.json();
|
|
} catch (e) {
|
|
console.error('Resend 2FA failed:', e);
|
|
return { success: false, message: 'Netzwerkfehler' };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Logout current user
|
|
* @returns {Promise<{success: boolean}>}
|
|
*/
|
|
export async function logout() {
|
|
try {
|
|
await fetch(`${API_BASE}/auth/logout`, {
|
|
method: 'POST',
|
|
credentials: 'same-origin'
|
|
});
|
|
} catch (e) {
|
|
console.error('Logout request failed:', e);
|
|
}
|
|
|
|
authState.isAuthenticated = false;
|
|
authState.user = null;
|
|
|
|
return { success: true };
|
|
}
|
|
|
|
/**
|
|
* Generic API helper for app-specific endpoints
|
|
* Usage: api.get('WarehouseStocktake/getActiveStocktakes')
|
|
* api.post('WarehouseStocktake/submitScan', { ... })
|
|
*/
|
|
export const api = {
|
|
/**
|
|
* GET request
|
|
* @param {string} endpoint - Endpoint path (e.g., 'WarehouseStocktake/getArticle?code=123')
|
|
* @returns {Promise<object>}
|
|
*/
|
|
get: async (endpoint) => {
|
|
try {
|
|
const res = await fetch(`${API_BASE}/${endpoint}`, {
|
|
credentials: 'same-origin'
|
|
});
|
|
|
|
// Check for auth errors
|
|
if (res.status === 401) {
|
|
authState.isAuthenticated = false;
|
|
authState.user = null;
|
|
return { success: false, error: 'Not authenticated', authError: true };
|
|
}
|
|
|
|
return await res.json();
|
|
} catch (e) {
|
|
console.error(`API GET ${endpoint} failed:`, e);
|
|
return { success: false, error: 'Netzwerkfehler' };
|
|
}
|
|
},
|
|
|
|
/**
|
|
* POST request with JSON body
|
|
* @param {string} endpoint - Endpoint path
|
|
* @param {object} data - Request body
|
|
* @returns {Promise<object>}
|
|
*/
|
|
post: async (endpoint, data = {}) => {
|
|
try {
|
|
const res = await fetch(`${API_BASE}/${endpoint}`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'same-origin',
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
// Check for auth errors
|
|
if (res.status === 401) {
|
|
authState.isAuthenticated = false;
|
|
authState.user = null;
|
|
return { success: false, error: 'Not authenticated', authError: true };
|
|
}
|
|
|
|
return await res.json();
|
|
} catch (e) {
|
|
console.error(`API POST ${endpoint} failed:`, e);
|
|
return { success: false, error: 'Netzwerkfehler' };
|
|
}
|
|
}
|
|
};
|
|
|
|
// Export API_BASE for components that need to build URLs
|
|
export { API_BASE };
|