initialization
This commit is contained in:
commit
9ff09693ed
92 files changed
+46209
No files matched your search
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Api\PasswordController;
|
||||
use Slim\App;
|
||||
use Slim\Interfaces\RouteCollectorProxyInterface as Group;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
||||
return function (App $app) {
|
||||
// Serve static frontend
|
||||
$app->get('/', function (Request $request, Response $response, $args) {
|
||||
$html = file_get_contents(__DIR__ . '/../templates/index.html');
|
||||
$response->getBody()->write($html);
|
||||
return $response->withHeader('Content-Type', 'text/html');
|
||||
});
|
||||
|
||||
// API routes
|
||||
$app->group('/api/v1', function (Group $group) {
|
||||
// Password generation endpoints
|
||||
$group->get('/passwords', PasswordController::class . ':getPasswordTypes');
|
||||
$group->get('/passwords/generators', PasswordController::class . ':getGenerators');
|
||||
$group->post('/passwords/generate', PasswordController::class . ':generatePasswords');
|
||||
|
||||
// NEW: Available wordlists endpoint for dynamic language dropdown
|
||||
$group->get('/passwords/wordlists', PasswordController::class . ':getAvailableWordlists');
|
||||
|
||||
// Health check
|
||||
$group->get('/health', function (Request $request, Response $response) {
|
||||
$response->getBody()->write(json_encode([
|
||||
'status' => 'healthy',
|
||||
'version' => $_ENV['APP_VERSION'] ?? '1.0.0',
|
||||
'timestamp' => date('c')
|
||||
]));
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
});
|
||||
|
||||
// Updated locales endpoint with fixed pattern validation
|
||||
$group->get('/locales/{lang:[A-Za-z_]+}', function (Request $request, Response $response, array $args) {
|
||||
$lang = $args['lang'];
|
||||
|
||||
// Updated supported languages list to match frontend and wordlists
|
||||
$supportedLangs = ['en', 'de', 'de_CH', 'fr', 'it', 'es', 'pt', 'ja', 'zh'];
|
||||
|
||||
if (!in_array($lang, $supportedLangs, true)) {
|
||||
$lang = 'en'; // fallback
|
||||
}
|
||||
|
||||
// Preserve Swiss German locale when available, otherwise fall back to German
|
||||
if ($lang === 'ch') {
|
||||
$lang = 'de';
|
||||
}
|
||||
if ($lang === 'de_CH' && !file_exists(__DIR__ . '/../locales/de_CH.json')) {
|
||||
$lang = 'de';
|
||||
}
|
||||
|
||||
$path = __DIR__ . "/../locales/{$lang}.json";
|
||||
if (!file_exists($path)) {
|
||||
return $response->withStatus(404);
|
||||
}
|
||||
|
||||
$content = file_get_contents($path);
|
||||
$response->getBody()->write($content);
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
// API documentation
|
||||
$app->get('/docs', function (Request $request, Response $response, $args) {
|
||||
$html = file_get_contents(__DIR__ . '/../templates/docs.html');
|
||||
$response->getBody()->write($html);
|
||||
return $response->withHeader('Content-Type', 'text/html');
|
||||
});
|
||||
*/
|
||||
|
||||
// Serve static assets
|
||||
$app->get('/assets/{type}/{file}', function (Request $request, Response $response, array $args) {
|
||||
$type = $args['type'];
|
||||
$file = $args['file'];
|
||||
$path = __DIR__ . "/../assets/{$type}/{$file}";
|
||||
|
||||
if (!file_exists($path)) {
|
||||
return $response->withStatus(404);
|
||||
}
|
||||
|
||||
$content = file_get_contents($path);
|
||||
$contentType = $type === 'css' ? 'text/css' : 'application/javascript';
|
||||
|
||||
$response->getBody()->write($content);
|
||||
return $response->withHeader('Content-Type', $contentType);
|
||||
});
|
||||
|
||||
// Serve locale files directly with improved pattern matching
|
||||
$app->get('/locales/{file:[A-Za-z_]+\.json}', function (Request $request, Response $response, array $args) {
|
||||
$file = $args['file'];
|
||||
$path = __DIR__ . "/../locales/{$file}";
|
||||
|
||||
if (!file_exists($path)) {
|
||||
return $response->withStatus(404);
|
||||
}
|
||||
|
||||
$content = file_get_contents($path);
|
||||
$response->getBody()->write($content);
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
});
|
||||
|
||||
// Main documentation route (English - default)
|
||||
$app->get('/docs', function ($request, $response) {
|
||||
$docFile = __DIR__ . '/../docs/index.html';
|
||||
|
||||
if (file_exists($docFile)) {
|
||||
$response->getBody()->write(file_get_contents($docFile));
|
||||
return $response->withHeader('Content-Type', 'text/html; charset=utf-8');
|
||||
} else {
|
||||
return $response->withStatus(404)->write('Documentation not found');
|
||||
}
|
||||
});
|
||||
|
||||
// Language-specific documentation routes
|
||||
$app->get('/docs-{lang}', function ($request, $response, array $args) {
|
||||
$lang = $args['lang'];
|
||||
|
||||
// Allowed languages
|
||||
$allowedLanguages = ['de', 'fr', 'es', 'it', 'ja', 'zh'];
|
||||
|
||||
if (!in_array($lang, $allowedLanguages)) {
|
||||
return $response->withStatus(302)->withHeader('Location', '/docs');
|
||||
}
|
||||
|
||||
$docFile = __DIR__ . "/../docs/docs-{$lang}.html";
|
||||
|
||||
if (file_exists($docFile)) {
|
||||
$response->getBody()->write(file_get_contents($docFile));
|
||||
return $response->withHeader('Content-Type', 'text/html; charset=utf-8');
|
||||
} else {
|
||||
// Fallback to English
|
||||
$fallbackFile = __DIR__ . '/../docs/index.html';
|
||||
if (file_exists($fallbackFile)) {
|
||||
$response->getBody()->write(file_get_contents($fallbackFile));
|
||||
return $response->withHeader('Content-Type', 'text/html; charset=utf-8');
|
||||
} else {
|
||||
return $response->withStatus(404)->write('Documentation not found');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Static assets for documentation
|
||||
$app->get('/docs/assets/{type}/{file}', function ($request, $response, array $args) {
|
||||
$type = $args['type'];
|
||||
$file = $args['file'];
|
||||
|
||||
// Security: prevent directory traversal
|
||||
if (strpos($file, '..') !== false || strpos($type, '..') !== false) {
|
||||
return $response->withStatus(403)->write('Access denied');
|
||||
}
|
||||
|
||||
$assetFile = __DIR__ . "/../docs/assets/{$type}/{$file}";
|
||||
|
||||
if (file_exists($assetFile)) {
|
||||
$mimeTypes = [
|
||||
'css' => 'text/css',
|
||||
'js' => 'application/javascript',
|
||||
'png' => 'image/png',
|
||||
'jpg' => 'image/jpeg',
|
||||
'svg' => 'image/svg+xml'
|
||||
];
|
||||
|
||||
$extension = pathinfo($file, PATHINFO_EXTENSION);
|
||||
$mimeType = $mimeTypes[$extension] ?? 'text/plain';
|
||||
|
||||
$response->getBody()->write(file_get_contents($assetFile));
|
||||
return $response->withHeader('Content-Type', $mimeType);
|
||||
} else {
|
||||
return $response->withStatus(404)->write('Asset not found');
|
||||
}
|
||||
});
|
||||
};
|
||||
Reference in new issue
Block a user