c7d3ec57c3
Commitd2217531(google-labs-jules SSRF fix) catastrophically deleted 11,500+ lines across 100+ files while fixing an unrelated IMAP issue. Restored from d2217531^ (pre-bad-commit state): Deleted files (fully restored): - app/api/{automation,classification_rules,comments,sharing}.py - app/middleware/upload_rate_limit.py - app/tasks/{automation_tasks,classify_document}.py - app/utils/{automation_hooks,classification_rules}.py - docs/AppleAppStoreCompliance.md - frontend/input.css, package.json, package-lock.json, tailwind.config.js - frontend/static/js/{annotations,claim,comments,sharing}.js - frontend/templates/{admin_connections,file_annotations,file_summary}.html - tests/{test_api_files_comprehensive,test_auth_extended,test_sharing, test_comments,test_connections,test_imap_profiles,test_api_sessions, test_automation,test_classification_rules,test_api_advanced_filters, test_api_classification_rules,test_upload_rate_limit,test_api_dropbox, test_classify_document,test_comments_ui,test_upload_to_icloud, test_api_onedrive_comprehensive,test_frontend_build,test_sentry, test_diagnostic,test_database,test_views_dropbox,test_local_auth}.py Truncated files (content restored): - app/{auth,config,main,models,celery_worker,database}.py - app/api/{__init__,api_tokens,diagnostic,dropbox,files,google_drive, integrations,local_auth,mobile,onedrive,pipelines,qr_auth, settings,url_upload}.py - app/middleware/upload_rate_limit.py - app/tasks/upload_to_nextcloud.py - app/utils/{allowed_types,settings_service,settings_sync,user_scope,webhook}.py - app/views/{base,dropbox,files,google_drive,onedrive,settings}.py - docs/{API,AuthenticationSetup,ConfigurationGuide,DatabaseConfiguration, DeploymentGuide,DropboxSetup,GoogleDriveSetup,KubernetesDeployment, MobileApp,OneDriveSetup,ProductionReadiness,SentrySetup, SocialLoginSetup,UserGuide}.md - frontend/static/{js/upload.js,styles.css} - frontend/templates/{api_tokens,base,devices,dropbox,dropbox_callback, file_view,files,google_drive,onedrive,onedrive_callback, signup}.html - frontend/translations/en.json - migrations/env.py - tests/{conftest,test_api_integrations,test_api_mobile,test_api_settings, test_api_tokens,test_audit_logs,test_duplicates,test_imap_tasks, test_setup_wizard,test_views_files_comprehensive}.py Security fixes kept from post-d2217531 commits: - app/utils/network.py: DNS SSRF fail-secure fix (06b0fced) - app/utils/file_operations.py: path traversal fix (1018ea17) - tests/test_imap_tasks.py: re-applied 4 is_private_ip mock patches Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> Agent-Logs-Url: https://github.com/christianlouis/DocuElevate/sessions/51133dd8-9bec-41ab-aa10-3de753634187
180 lines
9.3 KiB
HTML
180 lines
9.3 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>DocuElevate - Create Account</title>
|
||
<link rel="stylesheet" href="/static/styles.css" />
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||
integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA=="
|
||
crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||
</head>
|
||
<body class="bg-gray-100 min-h-screen flex items-center justify-center py-8">
|
||
<main class="bg-white rounded-lg shadow-lg p-8 max-w-md w-full" role="main">
|
||
<div class="flex justify-center mb-6">
|
||
<img src="/static/images/logo_writing.svg" alt="DocuElevate Logo" class="h-16">
|
||
</div>
|
||
|
||
<h1 class="text-2xl font-bold text-center text-gray-800 mb-2">Create your account</h1>
|
||
<p class="text-center text-gray-500 text-sm mb-6">Already have an account?
|
||
<a href="/login" class="text-blue-600 hover:text-blue-500 font-medium">Sign in</a>
|
||
</p>
|
||
|
||
<div
|
||
x-data="{
|
||
email: '',
|
||
username: '',
|
||
display_name: '',
|
||
password: '',
|
||
password_confirm: '',
|
||
loading: false,
|
||
error: '',
|
||
async submit() {
|
||
this.error = '';
|
||
if (this.username.length < 3 || this.username.length > 64) {
|
||
this.error = 'Username must be between 3 and 64 characters.';
|
||
return;
|
||
}
|
||
if (!/^[a-zA-Z0-9_-]+$/.test(this.username)) {
|
||
this.error = 'Username may only contain letters, numbers, hyphens, and underscores. Dots and other special characters are not allowed.';
|
||
return;
|
||
}
|
||
if (this.password !== this.password_confirm) {
|
||
this.error = 'Passwords do not match.';
|
||
return;
|
||
}
|
||
this.loading = true;
|
||
try {
|
||
const resp = await fetch('/api/auth/signup', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': '{{ csrf_token }}' },
|
||
body: JSON.stringify({
|
||
email: this.email,
|
||
username: this.username,
|
||
display_name: this.display_name || null,
|
||
password: this.password,
|
||
password_confirm: this.password_confirm
|
||
})
|
||
});
|
||
if (resp.ok) {
|
||
const data = await resp.json();
|
||
if (data.email_verification_required) {
|
||
window.location.href = '/verify-email-sent';
|
||
} else {
|
||
window.location.href = '/login?message=Account+created+successfully.+You+can+now+log+in.';
|
||
}
|
||
} else {
|
||
const data = await resp.json();
|
||
const detail = data.detail;
|
||
if (Array.isArray(detail)) {
|
||
this.error = detail.map(e => e.msg || String(e)).join(' ') || 'Registration failed. Please try again.';
|
||
} else {
|
||
this.error = detail || 'Registration failed. Please try again.';
|
||
}
|
||
}
|
||
} catch(e) {
|
||
this.error = 'Network error. Please try again.';
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
}
|
||
}"
|
||
>
|
||
<div x-show="error" x-cloak
|
||
class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded"
|
||
role="alert"
|
||
aria-live="polite">
|
||
<p x-text="error"></p>
|
||
</div>
|
||
|
||
<form @submit.prevent="submit" class="space-y-4" novalidate>
|
||
<div>
|
||
<label for="email" class="block text-sm font-medium text-gray-700">Email address <span aria-hidden="true" class="text-red-500">*</span></label>
|
||
<input
|
||
type="email" id="email" name="email" required autocomplete="email"
|
||
x-model="email"
|
||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50"
|
||
aria-required="true"
|
||
style="min-height:44px;"
|
||
>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="username" class="block text-sm font-medium text-gray-700">Username <span aria-hidden="true" class="text-red-500">*</span></label>
|
||
<input
|
||
type="text" id="username" name="username" required autocomplete="username"
|
||
x-model="username"
|
||
pattern="^[a-zA-Z0-9_-]+$"
|
||
minlength="3" maxlength="64"
|
||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50"
|
||
aria-required="true"
|
||
aria-describedby="username-hint"
|
||
style="min-height:44px;"
|
||
>
|
||
<p id="username-hint" class="mt-1 text-xs text-gray-500">3–64 characters. Letters, numbers, hyphens and underscores only.</p>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="display_name" class="block text-sm font-medium text-gray-700">Display name <span class="text-gray-400">(optional)</span></label>
|
||
<input
|
||
type="text" id="display_name" name="display_name" autocomplete="name"
|
||
x-model="display_name"
|
||
maxlength="255"
|
||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50"
|
||
style="min-height:44px;"
|
||
>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="password" class="block text-sm font-medium text-gray-700">Password <span aria-hidden="true" class="text-red-500">*</span></label>
|
||
<input
|
||
type="password" id="password" name="password" required autocomplete="new-password"
|
||
x-model="password"
|
||
minlength="8" maxlength="128"
|
||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50"
|
||
aria-required="true"
|
||
aria-describedby="password-hint"
|
||
style="min-height:44px;"
|
||
>
|
||
<p id="password-hint" class="mt-1 text-xs text-gray-500">Minimum 8 characters.</p>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="password_confirm" class="block text-sm font-medium text-gray-700">Confirm password <span aria-hidden="true" class="text-red-500">*</span></label>
|
||
<input
|
||
type="password" id="password_confirm" name="password_confirm" required autocomplete="new-password"
|
||
x-model="password_confirm"
|
||
minlength="8" maxlength="128"
|
||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50"
|
||
aria-required="true"
|
||
style="min-height:44px;"
|
||
>
|
||
</div>
|
||
|
||
<button
|
||
type="submit"
|
||
:disabled="loading"
|
||
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50"
|
||
style="min-height:44px;"
|
||
>
|
||
<span x-show="!loading">Create account</span>
|
||
<span x-show="loading" x-cloak>
|
||
<i class="fas fa-spinner fa-spin mr-2" aria-hidden="true"></i>Creating account…
|
||
</span>
|
||
</button>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="mt-6 text-center">
|
||
<a href="/" class="text-sm font-medium text-blue-600 hover:text-blue-500">
|
||
Return to Home
|
||
</a>
|
||
</div>
|
||
</main>
|
||
<div class="fixed bottom-4 text-center w-full text-xs text-gray-500">
|
||
DocuElevate {{ app_version|default('', true) }}
|
||
</div>
|
||
</body>
|
||
</html>
|