Import upstream v0.16.22, stripped

Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f
Enterprise-only files removed or emptied: 63
Enterprise-only snippets removed: 117 in 50 files
Dangling module declarations removed: 5
Cargo edits turning enterprise off: 14
Verification: clean
Enterprise feature gates left for rebuilt features: 19 in 18 files

Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
2026-09-18 10:21:56 -07:00
commit 7dae9b29fd
1650 changed files with 485521 additions and 0 deletions
@@ -0,0 +1,218 @@
<!DOCTYPE html>
<html lang="{{lang}}" dir="{{dir}}" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="x-apple-disable-message-reformatting" content="">
<meta name="color-scheme" content="light">
<meta name="supported-color-schemes" content="light">
<title>{{page_title}}</title>
<!--[if mso]>
<noscript><xml><o:OfficeDocumentSettings><o:AllowPNG/><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml></noscript>
<![endif]-->
<!--[if mso]>
<style type="text/css">body,table,td,div,a,span{font-family:Arial,Helvetica,sans-serif !important}</style>
<![endif]-->
<style type="text/css">
:root {
color-scheme: light only;
}
#outlook a {
padding: 0;
}
body {
margin: 0;
padding: 0;
width: 100% !important;
background-color: #f2f2f0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table,
td {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
a {
color: #185fa5;
}
@media only screen and (max-width:600px) {
.shell {
width: 100% !important;
}
.pad {
padding-left: 22px !important;
padding-right: 22px !important;
}
}
</style>
</head>
<body dir="{{dir}}" style="margin:0;padding:0;background-color:#f2f2f0;">
<div
style="display:none;font-size:1px;color:#f2f2f0;line-height:1px;max-height:0;max-width:0;opacity:0;overflow:hidden;">
{{page_title}}</div>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%"
style="background-color:#f2f2f0;">
<tr>
<td align="center" style="padding:32px 12px;">
<table role="presentation" class="shell" border="0" cellpadding="0" cellspacing="0" width="600"
style="width:600px;max-width:600px;background-color:#ffffff;border:1px solid #e5e5e3;border-radius:12px;overflow:hidden;">
<tr>
<td height="3" style="height:3px;line-height:3px;font-size:0;background-color:#1a1a18;">&nbsp;
</td>
</tr>
<tr>
<td align="center" class="pad" style="padding:30px 40px 8px 40px;">
<img src="{{logo_cid}}" width="180" alt=""
style="display:block;width:180px;max-width:180px;height:auto;border:0;">
</td>
</tr>
{{#if header}}
<tr>
<td class="pad" style="padding:14px 40px 0 40px;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td align="center"
style="padding:11px 16px;border-radius:8px;background-color:#f4f4f2;color:#1a1a18;font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;font-weight:600;line-height:1.4;">
{{header}}
</td>
</tr>
</table>
</td>
</tr>
{{/if header}}
{{#if event_title}}
<tr>
<td class="pad" style="padding:22px 40px 0 40px;">
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:23px;font-weight:600;line-height:1.28;letter-spacing:-0.3px;color:#1a1a18;">
{{event_title}}</div>
</td>
</tr>
{{/if event_title}}
{{#if event_description}}
<tr>
<td class="pad" style="padding:12px 40px 0 40px;">
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.6;color:#4a4a46;">
{{event_description}}</div>
</td>
</tr>
{{/if event_description}}
{{#if event_details}}
<tr>
<td class="pad" style="padding:22px 40px 0 40px;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%"
style="background-color:#f9f9f7;border:1px solid #ececea;border-radius:9px;">
<tr>
<td style="padding:6px 18px 10px 18px;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0"
width="100%">
{{#each event_details}}
<tr>
<td style="padding:10px 0 0 0;">
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:11px;font-weight:600;letter-spacing:0.7px;text-transform:uppercase;color:#87877f;">
{{key}}</div>
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:15px;line-height:1.5;color:#1a1a18;padding-top:3px;word-break:break-word;">
{{#if link}}<a href="{{link}}" target="_blank" style="color:#185fa5;text-decoration:underline;">{{/if link}}{{value}}{{#if link}}</a>{{/if link}}</div>
</td>
</tr>
{{/each event_details}}
</table>
</td>
</tr>
</table>
</td>
</tr>
{{/if event_details}}
{{#if attendees}}
<tr>
<td class="pad" style="padding:24px 40px 0 40px;">
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:11px;font-weight:600;letter-spacing:0.7px;text-transform:uppercase;color:#87877f;padding-bottom:8px;">
{{attendees_title}}</div>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
{{#each attendees}}
<tr>
<td
style="padding:4px 0;font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.45;color:#1a1a18;">
{{key}} <span style="color:#87877f;">{{value}}</span>
</td>
</tr>
{{/each attendees}}
</table>
</td>
</tr>
{{/if attendees}}
<tr>
<td class="pad" style="padding:26px 40px 0 40px;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td align="center" valign="middle"
style="border-radius:8px;background-color:#1a1a18;mso-padding-alt:13px 24px;">
<a href="{{action_url}}" target="_blank"
style="display:block;padding:13px 24px;font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:15px;font-weight:600;line-height:1;color:#ffffff;text-decoration:none;border-radius:8px;">{{action_name}}</a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="padding:0 0 30px 0;font-size:0;line-height:0;">&nbsp;</td>
</tr>
</table>
{{#if footer}}
<table role="presentation" class="shell" border="0" cellpadding="0" cellspacing="0" width="600"
style="width:600px;max-width:600px;">
<tr>
<td align="center" class="pad" style="padding:6px 40px 0 40px;">
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:12px;line-height:1.55;color:#87877f;">
{{footer}}</div>
</td>
</tr>
<tr>
<td style="padding:0 0 18px 0;font-size:0;line-height:0;">&nbsp;</td>
</tr>
</table>
{{/if footer}}
</td>
</tr>
</table>
</body>
</html>
File diff suppressed because one or more lines are too long
@@ -0,0 +1,299 @@
<!DOCTYPE html>
<html lang="{{lang}}" dir="{{dir}}" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="x-apple-disable-message-reformatting" content="">
<meta name="color-scheme" content="light">
<meta name="supported-color-schemes" content="light">
<title>{{page_title}}</title>
<!--[if mso]>
<noscript><xml><o:OfficeDocumentSettings><o:AllowPNG/><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml></noscript>
<![endif]-->
<!--[if mso]>
<style type="text/css">body,table,td,div,a,span{font-family:Arial,Helvetica,sans-serif !important}</style>
<![endif]-->
<style type="text/css">
:root {
color-scheme: light only;
}
#outlook a {
padding: 0;
}
body {
margin: 0;
padding: 0;
width: 100% !important;
background-color: #f2f2f0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table,
td {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
a {
color: #185fa5;
}
.bar-info {
background-color: #1f7a4d;
}
.bar-warning {
background-color: #b26a00;
}
.bar-danger {
background-color: #c02b3f;
}
.banner-info {
background-color: #eaf6ef;
color: #14603b;
}
.banner-warning {
background-color: #fdf3e3;
color: #8a4b00;
}
.banner-danger {
background-color: #fdecee;
color: #96202f;
}
.btn-info {
background-color: #1f7a4d;
}
.btn-warning {
background-color: #b26a00;
}
.btn-danger {
background-color: #c02b3f;
}
@media only screen and (max-width:600px) {
.shell {
width: 100% !important;
}
.pad {
padding-left: 22px !important;
padding-right: 22px !important;
}
.stack {
display: block !important;
width: 100% !important;
padding: 0 0 10px 0 !important;
}
}
</style>
</head>
<body dir="{{dir}}" style="margin:0;padding:0;background-color:#f2f2f0;">
<div style="display:none;font-size:1px;color:#f2f2f0;line-height:1px;max-height:0;max-width:0;opacity:0;overflow:hidden;">
{{page_title}}</div>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%"
style="background-color:#f2f2f0;">
<tr>
<td align="center" style="padding:32px 12px;">
<table role="presentation" class="shell" border="0" cellpadding="0" cellspacing="0" width="600"
style="width:600px;max-width:600px;background-color:#ffffff;border:1px solid #e5e5e3;border-radius:12px;overflow:hidden;">
<tr>
<td class="bar-{{color}}" height="3"
style="height:3px;line-height:3px;font-size:0;background-color:#1a1a18;">&nbsp;</td>
</tr>
<tr>
<td align="center" class="pad" style="padding:30px 40px 8px 40px;">
<img src="{{logo_cid}}" width="180" alt=""
style="display:block;width:180px;max-width:180px;height:auto;border:0;">
</td>
</tr>
{{#if header}}
<tr>
<td class="pad" style="padding:14px 40px 0 40px;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td class="banner-{{color}}" align="center"
style="padding:11px 16px;border-radius:8px;background-color:#f4f4f2;color:#1a1a18;font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;font-weight:600;line-height:1.4;">
{{header}}
</td>
</tr>
</table>
</td>
</tr>
{{/if header}}
{{#if event_title}}
<tr>
<td class="pad" style="padding:22px 40px 0 40px;">
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:23px;font-weight:600;line-height:1.28;letter-spacing:-0.3px;color:#1a1a18;">
{{event_title}}</div>
</td>
</tr>
{{/if event_title}}
{{#if event_description}}
<tr>
<td class="pad" style="padding:12px 40px 0 40px;">
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.6;color:#4a4a46;">
{{event_description}}</div>
</td>
</tr>
{{/if event_description}}
{{#if event_details}}
<tr>
<td class="pad" style="padding:22px 40px 0 40px;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%"
style="background-color:#f9f9f7;border:1px solid #ececea;border-radius:9px;">
<tr>
<td style="padding:6px 18px 10px 18px;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0"
width="100%">
{{#each event_details}}
<tr>
<td style="padding:10px 0 0 0;">
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:11px;font-weight:600;letter-spacing:0.7px;text-transform:uppercase;color:#87877f;">
{{key}}{{#if changed}}<span
style="display:inline-block;margin-left:7px;padding:2px 7px;border-radius:999px;background-color:#1a1a18;color:#ffffff;font-size:9px;font-weight:700;letter-spacing:0.4px;text-transform:uppercase;">{{changed}}</span>{{/if changed}}
</div>
{{#if old_value}}<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.5;color:#a3a39c;text-decoration:line-through;padding-top:3px;">
{{old_value}}</div>{{/if old_value}}
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:15px;line-height:1.5;color:#1a1a18;padding-top:3px;word-break:break-word;">
{{#if link}}<a href="{{link}}" target="_blank" style="color:#185fa5;text-decoration:underline;">{{/if link}}{{value}}{{#if link}}</a>{{/if link}}</div>
</td>
</tr>
{{/each event_details}}
</table>
</td>
</tr>
</table>
</td>
</tr>
{{/if event_details}}
{{#if attendees}}
<tr>
<td class="pad" style="padding:24px 40px 0 40px;">
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:11px;font-weight:600;letter-spacing:0.7px;text-transform:uppercase;color:#87877f;padding-bottom:8px;">
{{attendees_title}}</div>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
{{#each attendees}}
<tr>
<td
style="padding:4px 0;font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.45;color:#1a1a18;">
{{key}} <span style="color:#87877f;">{{value}}</span>
</td>
</tr>
{{/each attendees}}
</table>
</td>
</tr>
{{/if attendees}}
{{#if rsvp}}
<tr>
<td class="pad" style="padding:26px 40px 0 40px;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td height="1"
style="height:1px;line-height:1px;font-size:0;background-color:#ececea;">&nbsp;
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td class="pad" align="center" style="padding:20px 40px 0 40px;">
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.5;color:#4a4a46;">
{{rsvp}}</div>
</td>
</tr>
<tr>
<td class="pad" style="padding:14px 34px 4px 34px;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
{{#each actions}}
<td class="stack" width="33.33%" align="center" valign="middle"
style="padding:0 6px;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0"
width="100%">
<tr>
<td class="btn-{{color}}" align="center" valign="middle"
style="border-radius:8px;background-color:#1a1a18;mso-padding-alt:12px 8px;">
<a href="{{action_url}}" target="_blank"
style="display:block;padding:12px 8px;font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;font-weight:600;line-height:1;color:#ffffff;text-decoration:none;border-radius:8px;">{{action_name}}</a>
</td>
</tr>
</table>
</td>
{{/each actions}}
</tr>
</table>
</td>
</tr>
{{/if rsvp}}
<tr>
<td style="padding:0 0 30px 0;font-size:0;line-height:0;">&nbsp;</td>
</tr>
</table>
{{#if footer}}
<table role="presentation" class="shell" border="0" cellpadding="0" cellspacing="0" width="600"
style="width:600px;max-width:600px;">
{{#each footer}}
<tr>
<td align="center" class="pad" style="padding:6px 40px 0 40px;">
<div
style="font-family:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:12px;line-height:1.55;color:#87877f;">
{{key}}</div>
</td>
</tr>
{{/each footer}}
<tr>
<td style="padding:0 0 18px 0;font-size:0;line-height:0;">&nbsp;</td>
</tr>
</table>
{{/if footer}}
</td>
</tr>
</table>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
+606
View File
@@ -0,0 +1,606 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="referrer" content="no-referrer">
<title>Sign in</title>
<style>
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0
}
:root {
--bg: #f5f5f4;
--card: #fff;
--border: #e5e5e3;
--text: #1a1a18;
--muted: #6b6b67;
--accent: #1a1a18;
--accent-fg: #fff;
--info: #185fa5;
--success: #0f7a3c;
--radius: 10px;
--input-bg: #fafaf9;
}
@media(prefers-color-scheme:dark) {
:root {
--bg: #18181b;
--card: #1f1f23;
--border: #2e2e33;
--text: #f4f4f2;
--muted: #9b9b95;
--accent: #f4f4f2;
--accent-fg: #18181b;
--info: #5faee3;
--success: #58c98a;
--input-bg: #2a2a2e;
}
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
background: var(--bg);
color: var(--text);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 1rem;
}
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 0.5rem 2.25rem 2rem;
width: 100%;
max-width: 384px;
}
.logo-wrap {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 72px;
margin: 0.25rem auto 0.5rem;
}
.logo-wrap svg.default-logo {
display: block;
width: calc(100% + 1rem);
height: auto;
margin: -0.25rem auto 0.1rem;
max-width: 320px;
}
.logo-wrap[data-loading] .default-logo {
visibility: hidden;
}
.logo-wrap img.custom-logo {
display: block;
max-width: 220px;
max-height: 96px;
width: auto;
height: auto;
object-fit: contain;
}
.default-logo .wordmark {
fill: var(--text)
}
.default-logo .symbol {
fill: #db2d54
}
h1 {
font-size: 1.125rem;
font-weight: 600;
letter-spacing: -.015em;
margin-bottom: .25rem
}
.sub {
font-size: .8125rem;
color: var(--muted);
margin-bottom: 1.75rem
}
.alert {
display: flex;
align-items: flex-start;
gap: .625rem;
padding: .625rem .75rem;
background: color-mix(in srgb, #db2d54 10%, transparent);
border: 1px solid color-mix(in srgb, #db2d54 30%, transparent);
border-radius: 8px;
font-size: .8125rem;
color: #a0192f;
margin-bottom: .875rem;
}
.alert.success {
background: color-mix(in srgb, #0f7a3c 10%, transparent);
border-color: color-mix(in srgb, #0f7a3c 30%, transparent);
color: #0f7a3c;
}
@media(prefers-color-scheme:dark) {
.alert {
color: #f4839a
}
.alert.success {
color: #58c98a;
}
}
.alert svg {
flex-shrink: 0;
margin-top: 1px
}
.fields {
display: flex;
flex-direction: column;
gap: .875rem
}
.field label {
font-size: .75rem;
font-weight: 500;
color: var(--muted);
letter-spacing: .03em;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: .3125rem;
}
input[type=text],
input[type=password],
input[type=email] {
width: 100%;
padding: .5625rem .75rem;
font-size: .9375rem;
font-family: inherit;
background: var(--input-bg);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text);
outline: none;
transition: border-color .15s;
-webkit-appearance: none;
}
input[type=text]:focus,
input[type=password]:focus,
input[type=email]:focus {
border-color: color-mix(in srgb, var(--info) 60%, transparent);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--info) 12%, transparent);
}
input[type=text]::placeholder,
input[type=password]::placeholder,
input[type=email]::placeholder {
color: var(--muted);
opacity: .7
}
#otp {
letter-spacing: .2em;
font-size: 1.0625rem;
text-align: center;
font-variant-numeric: tabular-nums
}
#device-code {
letter-spacing: .15em;
font-size: 1.0625rem;
text-align: center;
text-transform: uppercase;
font-variant-numeric: tabular-nums;
}
.btn {
width: 100%;
margin-top: .375rem;
padding: .625rem 0;
font-size: .9375rem;
font-weight: 500;
font-family: inherit;
background: var(--accent);
color: var(--accent-fg);
border: none;
border-radius: 8px;
cursor: pointer;
letter-spacing: -.01em;
transition: opacity .15s;
}
.btn:hover {
opacity: .88
}
.btn:active {
opacity: .75;
transform: scale(.99)
}
.btn[disabled] {
opacity: .55;
cursor: not-allowed;
transform: none;
}
[hidden] {
display: none !important;
}
</style>
</head>
<body>
<div class="card">
<div class="logo-wrap" id="logo-wrap" data-loading>
<svg class="default-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 680.5 252.1" aria-label="Logo">
<path class="wordmark"
d="M227.8 143.6c.3 4.2 2.1 7.6 5.1 10.1 3.1 2.5 7.1 3.8 12.1 3.8 4.3 0 7.9-.9 10.5-2.8 2.7-1.9 4-4.5 4-7.8 0-2.4-.7-4.3-2.2-5.7-1.5-1.4-3.4-2.5-6-3.2-2.5-.7-6-1.5-10.6-2.3-4.6-.8-8.6-1.9-11.9-3.2-3.3-1.3-6-3.3-8.1-6.1-2.1-2.7-3.1-6.3-3.1-10.7 0-4.1 1.1-7.7 3.2-10.9s5.1-5.7 9-7.4c3.8-1.8 8.2-2.6 13.2-2.6 5.1 0 9.6 1 13.7 2.9 4 1.9 7.2 4.5 9.5 7.8s3.6 7.1 3.8 11.4h-11.5c-.4-3.7-2-6.6-4.8-8.9-2.8-2.2-6.3-3.4-10.6-3.4-4.1 0-7.5.9-9.9 2.7-2.5 1.8-3.7 4.3-3.7 7.6 0 2.3.7 4.1 2.2 5.5 1.5 1.4 3.4 2.4 5.9 3.1 2.4.7 5.9 1.4 10.5 2.2 4.6.8 8.6 1.9 11.9 3.3 3.3 1.4 6 3.4 8.2 6 2.1 2.6 3.2 6.1 3.2 10.5 0 4.2-1.1 8-3.4 11.3-2.2 3.3-5.4 5.9-9.4 7.8-4 1.9-8.6 2.8-13.7 2.8-5.6 0-10.6-1-14.9-3.1-4.3-2-7.6-4.9-10-8.5-2.4-3.6-3.7-7.8-3.7-12.5l11.5.3zM278.5 102.1l11-2.1v14.6h12.6v9.7h-12.6v27.2c0 2 .4 3.5 1.2 4.3.8.9 2.2 1.3 4.2 1.3h8.4v9.7h-10.6c-5 0-8.6-1.2-10.8-3.5-2.2-2.3-3.4-5.9-3.4-10.7v-50.5zM356.8 114.6v52.2h-9.7l-1.2-7.9c-1.8 2.6-4.2 4.7-7 6.2-2.9 1.6-6.2 2.3-10 2.3-4.8 0-9-1.1-12.7-3.2-3.7-2.1-6.7-5.2-8.8-9.3-2.1-4-3.2-8.8-3.2-14.2 0-5.3 1.1-10 3.2-14s5.1-7.2 8.8-9.4c3.7-2.2 7.9-3.3 12.6-3.3 3.9 0 7.2.7 10.1 2.2 2.9 1.5 5.2 3.5 6.9 6.1l1.3-7.6h9.7zm-15.1 38.7c2.8-3.2 4.2-7.3 4.2-12.4 0-5.2-1.4-9.4-4.2-12.6-2.8-3.3-6.5-4.9-11-4.9-4.6 0-8.2 1.6-11 4.8-2.8 3.2-4.2 7.4-4.2 12.5 0 5.2 1.4 9.4 4.2 12.6 2.8 3.2 6.5 4.8 11 4.8s8.2-1.6 11-4.8zM365.5 97.5l11-2.1v71.3h-11V97.5zM380.3 114.6h11.6l11.9 39.9 11.9-39.9h10.1l11.4 39.9 12.3-39.9h11.2l-17.3 52.2h-11.8l-11-35.5-11.4 35.5-11.9.1-17-52.3zM513.7 114.6v52.2H504l-1.2-7.9c-1.8 2.6-4.2 4.7-7 6.2-2.9 1.6-6.2 2.3-10 2.3-4.8 0-9-1.1-12.7-3.2-3.7-2.1-6.7-5.2-8.8-9.3-2.1-4-3.2-8.8-3.2-14.2 0-5.3 1.1-10 3.2-14s5.1-7.2 8.8-9.4c3.7-2.2 7.9-3.3 12.6-3.3 3.9 0 7.2.7 10.1 2.2 2.9 1.5 5.2 3.5 6.9 6.1l1.3-7.6h9.7zm-15.1 38.7c2.8-3.2 4.2-7.3 4.2-12.4 0-5.2-1.4-9.4-4.2-12.6-2.8-3.3-6.5-4.9-11-4.9-4.6 0-8.2 1.6-11 4.8-2.8 3.2-4.2 7.4-4.2 12.5 0 5.2 1.4 9.4 4.2 12.6 2.8 3.2 6.5 4.8 11 4.8 4.6 0 8.2-1.6 11-4.8zM551.3 114.6v10.3h-4.9c-4.6 0-7.8 1.5-9.9 4.4-2 3-3.1 6.7-3.1 11.3v26.2h-11v-52.2h9.8l1.2 7.8c1.5-2.4 3.4-4.4 5.8-5.8 2.4-1.4 5.6-2.1 9.6-2.1h2.5zM556.3 102.1l11-2.1v14.6h12.6v9.7h-12.6v27.2c0 2 .4 3.5 1.2 4.3.8.9 2.2 1.3 4.2 1.3h8.4v9.7h-10.6c-5 0-8.6-1.2-10.8-3.5s-3.4-5.9-3.4-10.7v-50.5z" />
<path class="symbol"
d="M149.1 84.7h-4.8l-44.8 25.9v8.3l44.8 25.9h4.8l44.8-25.9v-8.3l-44.8-25.9zm32.9 30h-35.3V94.4l35.3 20.3zm-35.3 20.4-35.3-20.4 27-15.6v20.2l6.3 3.6h22.9l-20.9 12.2zM99.5 129.9v11l44.8 25.9h4.8l44.8-25.9v-11l-47.2 27.3zM187.3 166.8l6.6-3.8v-11l-25.7 14.8zM99.5 163l6.6 3.8h19.1L99.5 152z" />
</svg>
</div>
<h1 id="title">Sign in</h1>
<p class="sub" id="subtitle">Enter your credentials to continue</p>
<div class="alert" id="alert" hidden aria-live="polite">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="8" x2="12" y2="12" />
<line x1="12" y1="16" x2="12.01" y2="16" />
</svg>
<span id="alert-msg"></span>
</div>
<form class="fields" id="login-form" novalidate>
<div class="field" id="field-username">
<label for="username">Username</label>
<input id="username" name="username" type="text" placeholder="[email protected]" autocomplete="username"
autocapitalize="none" autocorrect="off" spellcheck="false" required>
</div>
<div class="field" id="field-password">
<label for="password">Password</label>
<input id="password" name="password" type="password" placeholder="••••••••"
autocomplete="current-password" required>
</div>
<div class="field" id="field-device-code" hidden>
<label for="device-code">Device code</label>
<input id="device-code" name="device-code" type="text" placeholder="XXXX-XXXX" autocomplete="off"
autocapitalize="characters" spellcheck="false">
</div>
<div class="field" id="field-otp" hidden>
<label for="otp">One-time code</label>
<input id="otp" name="otp" type="text" placeholder="000000" maxlength="6" inputmode="numeric"
pattern="\d{6}" autocomplete="one-time-code">
</div>
<button type="submit" class="btn" id="submit-btn">Sign in</button>
</form>
</div>
<script>
(function () {
'use strict';
var $ = function (id) { return document.getElementById(id); };
function setText(el, text) {
// textContent is XSS-safe: never parses HTML.
el.textContent = text == null ? '' : String(text);
}
function show(el) { if (el) el.hidden = false; }
function hide(el) { if (el) el.hidden = true; }
function showError(msg) {
var a = $('alert');
a.classList.remove('success');
setText($('alert-msg'), msg);
show(a);
}
function showSuccess(msg) {
var a = $('alert');
a.classList.add('success');
setText($('alert-msg'), msg);
show(a);
}
function clearAlert() { hide($('alert')); }
var url = new URL(window.location.href);
var params = url.searchParams;
var isDevice = /\/device(\/|$)/.test(url.pathname);
// Collected OAuth params for the code flow
var oauth = {
client_id: params.get('client_id') || '',
redirect_uri: params.get('redirect_uri'),
scope: params.get('scope'),
state: params.get('state'),
nonce: params.get('nonce'),
code_challenge: params.get('code_challenge'),
code_challenge_method: params.get('code_challenge_method'),
resource: params.getAll('resource')
};
// This page is the OAuth authorization screen used by apps
if (!isDevice && !oauth.redirect_uri) {
hide($('login-form'));
setText($('title'), 'Sign in with an app');
setText($('subtitle'), 'This page is opened automatically by your mail, calendar or contacts app to authorize access to your account.');
showError('This sign-in page cannot be used directly. Please start the sign-in from your app instead. (The required "redirect_uri" parameter is missing.)');
return;
}
// Prefill username from login_hint
var loginHint = params.get('login_hint');
if (loginHint) $('username').value = loginHint;
// Device-flow specific UI
if (isDevice) {
setText($('title'), 'Authorize device');
setText($('subtitle'), 'Sign in to approve this device.');
show($('field-device-code'));
var prefillCode = params.get('code');
if (prefillCode) $('device-code').value = prefillCode;
}
var inMfa = false;
var lastCreds = null; // { account_name, account_secret } cached to resubmit with OTP
function enterMfaMode() {
inMfa = true;
hide($('field-username'));
hide($('field-password'));
if (isDevice) hide($('field-device-code'));
show($('field-otp'));
setText($('title'), 'Two-factor authentication');
setText($('subtitle'), 'Enter the 6-digit code from your authenticator app.');
clearAlert();
setTimeout(function () { $('otp').focus(); }, 0);
}
(function loadCustomLogo() {
var wrap = $('logo-wrap');
function showDefault() { wrap.removeAttribute('data-loading'); }
var target = '/logo';
if (loginHint) {
var at = loginHint.lastIndexOf('@');
if (at !== -1 && at < loginHint.length - 1) {
target = '/logo?domain=' + encodeURIComponent(loginHint.slice(at + 1).toLowerCase());
}
}
fetch(target, { method: 'GET', credentials: 'same-origin' })
.then(function (res) {
if (!res.ok) return null;
var ct = (res.headers.get('content-type') || '').toLowerCase();
if (ct.indexOf('image/') !== 0) return null;
return res.blob();
})
.then(function (blob) {
if (!blob) { showDefault(); return; }
var objectUrl = URL.createObjectURL(blob);
var img = new Image();
img.className = 'custom-logo';
img.alt = 'Logo';
img.onload = function () {
while (wrap.firstChild) wrap.removeChild(wrap.firstChild);
wrap.appendChild(img);
wrap.removeAttribute('data-loading');
};
img.onerror = function () {
URL.revokeObjectURL(objectUrl);
showDefault();
};
img.src = objectUrl;
})
.catch(function (err) {
console.log('Custom logo unavailable:', err);
showDefault();
});
})();
function buildRequest(creds, otpValue) {
if (isDevice) {
var req = {
type: 'authDevice',
accountName: creds.account_name,
accountSecret: creds.account_secret,
code: ($('device-code').value || '').trim()
};
if (otpValue) req.mfaToken = otpValue;
return req;
}
var r = {
type: 'authCode',
accountName: creds.account_name,
accountSecret: creds.account_secret,
clientId: oauth.client_id || ''
};
if (oauth.redirect_uri) r.redirectUri = oauth.redirect_uri;
if (oauth.scope) r.scope = oauth.scope;
if (oauth.state) r.state = oauth.state;
if (oauth.nonce) r.nonce = oauth.nonce;
if (oauth.code_challenge) r.codeChallenge = oauth.code_challenge;
if (oauth.code_challenge_method) r.codeChallengeMethod = oauth.code_challenge_method;
if (oauth.resource && oauth.resource.length) r.resource = oauth.resource;
if (otpValue) r.mfaToken = otpValue;
return r;
}
function performRedirect(clientCode, issuer) {
// Build redirect_uri?code=<client_code>&state=<state>
var target;
try {
if (!oauth.redirect_uri) throw new Error('missing redirect_uri');
target = new URL(oauth.redirect_uri);
} catch (e) {
console.log('Invalid or missing redirect_uri:', oauth.redirect_uri, e);
showError('Temporary server failure. If the problem persists, contact your administrator.');
return;
}
target.searchParams.set('code', clientCode);
if (oauth.state) target.searchParams.set('state', oauth.state);
target.searchParams.set('iss', issuer || url.origin);
window.location.assign(target.toString());
}
function handleResponse(resp) {
if (!resp || typeof resp !== 'object' || typeof resp.type !== 'string') {
console.log('Malformed login response:', resp);
showError('Temporary server failure. If the problem persists, contact your administrator.');
return;
}
switch (resp.type) {
case 'authenticated':
if (typeof resp.client_code !== 'string') {
console.log('Missing client_code in response:', resp);
showError('Temporary server failure. If the problem persists, contact your administrator.');
return;
}
performRedirect(resp.client_code, resp.iss);
return;
case 'verified':
hide($('login-form'));
setText($('title'), 'Device authorized');
setText($('subtitle'), 'You have successfully authorized this device. You may now close this window.');
clearAlert();
showSuccess('Device verified.');
return;
case 'mfaRequired':
enterMfaMode();
return;
case 'failure':
// Reset MFA state on failure so the user can retry credentials.
if (inMfa) {
inMfa = false;
show($('field-username'));
show($('field-password'));
if (isDevice) show($('field-device-code'));
hide($('field-otp'));
$('otp').value = '';
setText($('title'), isDevice ? 'Authorize device' : 'Sign in');
setText($('subtitle'), isDevice
? 'Sign in to approve this device.'
: 'Enter your credentials to continue');
}
showError('Invalid username or password. Please try again.');
return;
default:
console.log('Unknown login response type:', resp);
showError('Temporary server failure. If the problem persists, contact your administrator.');
}
}
function submitLogin(e) {
if (e) e.preventDefault();
clearAlert();
var creds;
if (inMfa) {
var otp = ($('otp').value || '').trim();
if (!otp) { showError('Please enter your one-time code.'); return; }
if (!lastCreds) {
// Safety net: shouldn't happen.
inMfa = false;
show($('field-username'));
show($('field-password'));
hide($('field-otp'));
showError('Session expired. Please sign in again.');
return;
}
creds = lastCreds;
var body = buildRequest(creds, otp);
postLogin(body);
return;
}
var username = ($('username').value || '').trim();
var password = $('password').value || '';
if (!username || !password) {
showError('Please enter your username and password.');
return;
}
if (isDevice) {
var devCode = ($('device-code').value || '').trim();
if (!devCode) {
showError('Please enter the device code.');
return;
}
}
creds = { account_name: username, account_secret: password };
lastCreds = creds;
postLogin(buildRequest(creds, null));
}
function postLogin(body) {
var btn = $('submit-btn');
btn.disabled = true;
fetch('/api/auth', {
method: 'POST',
credentials: 'same-origin',
cache: 'no-store',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(body)
}).then(function (res) {
if (res.status !== 200) {
return res.text().then(function (txt) {
console.log('Login endpoint returned HTTP', res.status, txt);
throw new Error('http ' + res.status);
});
}
return res.json().catch(function (err) {
console.log('Failed to parse login response JSON:', err);
throw err;
});
}).then(function (json) {
handleResponse(json);
}).catch(function (err) {
console.log('Login request failed:', err);
showError('Temporary server failure. If the problem persists, contact your administrator.');
}).then(function () {
btn.disabled = false;
});
}
$('login-form').addEventListener('submit', submitLogin);
// Digit-only filter on OTP and auto-submit on 6 digits.
$('otp').addEventListener('input', function () {
this.value = this.value.replace(/\D/g, '');
if (this.value.length === 6) submitLogin();
});
// Focus the first visible empty field.
setTimeout(function () {
if (!$('username').value) { $('username').focus(); return; }
if (!$('password').value) { $('password').focus(); return; }
if (isDevice && !$('device-code').value) { $('device-code').focus(); return; }
}, 0);
})();
</script>
</body>
</html>
File diff suppressed because one or more lines are too long
Binary file not shown.