Files
gh-christianlouis-docuelevate/frontend/templates/signup.html
T
copilot-swe-agent[bot] c7d3ec57c3 fix: restore all code deleted/truncated by d2217531 Jules SSRF commit
Commit d2217531 (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
2026-03-23 23:52:39 +00:00

180 lines
9.3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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">364 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&hellip;
</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>