forked from andyburke/autonomous.contact
feature: remember if someone has logged in and default to a login screen
fix: some includes needed updating feature: some more overrides
This commit is contained in:
parent
ebf0e4428e
commit
7b3494cc32
12 changed files with 90 additions and 55 deletions
|
|
@ -6,10 +6,11 @@ import { SESSION, SESSIONS } from '../../../models/session.ts';
|
||||||
import { TOTP_ENTRIES } from '../../../models/totp_entry.ts';
|
import { TOTP_ENTRIES } from '../../../models/totp_entry.ts';
|
||||||
import { encodeBase64 } from '@std/encoding/base64';
|
import { encodeBase64 } from '@std/encoding/base64';
|
||||||
import parse_body from '../../../utils/bodyparser.ts';
|
import parse_body from '../../../utils/bodyparser.ts';
|
||||||
import { get_session, get_user, PRECHECK_TABLE, require_user, SESSION_ID_TOKEN, SESSION_SECRET_TOKEN } from '../../../utils/prechecks.ts';
|
import { AUTHED_BEFORE_COOKIE_ID, get_session, get_user, PRECHECK_TABLE, require_user, SESSION_ID_TOKEN, SESSION_SECRET_TOKEN } from '../../../utils/prechecks.ts';
|
||||||
import * as bcrypt from '@da/bcrypt';
|
import * as bcrypt from '@da/bcrypt';
|
||||||
import { verifyTotp } from '../../../utils/totp.ts';
|
import { verifyTotp } from '../../../utils/totp.ts';
|
||||||
|
|
||||||
|
const AUTHED_BEFORE_EXPIRATION: number = 399 * (24 * (60 * (60 * 1_000))); // 399 days
|
||||||
const DEFAULT_SESSION_TIME: number = 365 * (24 * (60 * (60 * 1_000))); // 365 days
|
const DEFAULT_SESSION_TIME: number = 365 * (24 * (60 * (60 * 1_000))); // 365 days
|
||||||
|
|
||||||
export const PRECHECKS: PRECHECK_TABLE = {};
|
export const PRECHECKS: PRECHECK_TABLE = {};
|
||||||
|
|
@ -206,6 +207,7 @@ export async function create_new_session(session_settings: SESSION_INFO): Promis
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
|
|
||||||
const expires_in_utc = new Date(session.timestamps.expires).toUTCString();
|
const expires_in_utc = new Date(session.timestamps.expires).toUTCString();
|
||||||
|
headers.append('Set-Cookie', `${AUTHED_BEFORE_COOKIE_ID}=1; Path=/; Secure; Expires=${new Date(new Date(now).valueOf() + AUTHED_BEFORE_EXPIRATION).toUTCString()}`);
|
||||||
headers.append('Set-Cookie', `${SESSION_ID_TOKEN}=${session.id}; Path=/; Secure; Expires=${expires_in_utc}`);
|
headers.append('Set-Cookie', `${SESSION_ID_TOKEN}=${session.id}; Path=/; Secure; Expires=${expires_in_utc}`);
|
||||||
headers.append(`x-${SESSION_ID_TOKEN}`, session.id);
|
headers.append(`x-${SESSION_ID_TOKEN}`, session.id);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,15 @@ body {
|
||||||
/* fixed height? */
|
/* fixed height? */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#background-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,14 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>autonomous.contact</title>
|
<title><!-- #include "./files/settings/title.txt" or "./title.txt" --></title>
|
||||||
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png" ></link>
|
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png" ></link>
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32x32.png" ></link>
|
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32x32.png" ></link>
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16x16.png" ></link>
|
<link rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16x16.png" ></link>
|
||||||
|
|
||||||
<link rel="stylesheet" href="/base.css"></link>
|
<link rel="stylesheet" href="/base.css"></link>
|
||||||
|
<link rel="stylesheet" href="/files/custom.css"></link>
|
||||||
|
|
||||||
<!-- inlining these to force them to be scoped for everything else -->
|
<!-- inlining these to force them to be scoped for everything else -->
|
||||||
<script type="text/javascript"><!-- #include "./js/_utils.js" --></script>
|
<script type="text/javascript"><!-- #include "./js/_utils.js" --></script>
|
||||||
|
|
@ -45,6 +46,8 @@
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div id="background-container"></div>
|
||||||
|
|
||||||
<!-- #include "./signup_login_wall.html" -->
|
<!-- #include "./signup_login_wall.html" -->
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,13 @@ const api = {
|
||||||
...__options,
|
...__options,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME: this will break with different server settings
|
||||||
|
// TODO: we need the cookie names here to match any configured on the server
|
||||||
const session_id = (document.cookie.match(
|
const session_id = (document.cookie.match(
|
||||||
/^(?:.*;)?\s*session_id\s*=\s*([^;]+)(?:.*)?$/,
|
/^(?:.*;)?\s*session_id\s*=\s*([^;]+)(?:.*)?$/,
|
||||||
) || [, null])[1];
|
) || [, null])[1];
|
||||||
|
|
||||||
|
// FIXME: this will break with different server settings
|
||||||
// TODO: this wasn't really intended to be persisted in a cookie
|
// TODO: this wasn't really intended to be persisted in a cookie
|
||||||
const session_secret = (document.cookie.match(
|
const session_secret = (document.cookie.match(
|
||||||
/^(?:.*;)?\s*session_secret\s*=\s*([^;]+)(?:.*)?$/,
|
/^(?:.*;)?\s*session_secret\s*=\s*([^;]+)(?:.*)?$/,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,19 @@
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: all 0.33s;
|
transition: all 0.33s ease;
|
||||||
|
animation: slideIn 0.4s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#login-tab .tab-content {
|
#login-tab .tab-content {
|
||||||
|
|
@ -49,52 +61,17 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- #include "./files/settings/signup_pitch.md" or "./signup_pitch.default.md" -->
|
<!-- #include "./files/settings/signup_pitch.html" or "./files/settings/signup_pitch.md" or "./signup_pitch.default.md" -->
|
||||||
|
|
||||||
<div class="limiter">
|
<div class="limiter">
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<div id="login-tab" class="tab">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="signup-login-tabs"
|
|
||||||
id="login-tab-input"
|
|
||||||
class="tab-switch"
|
|
||||||
checked="checked"
|
|
||||||
/>
|
|
||||||
<label for="login-tab-input" class="tab-label">
|
|
||||||
<div class="label">Log In</div>
|
|
||||||
</label>
|
|
||||||
<div class="tab-content">
|
|
||||||
<form data-smart="true" data-method="POST" id="login-form" action="/api/auth">
|
|
||||||
<script>
|
|
||||||
{
|
|
||||||
const form = document.currentScript.closest("form");
|
|
||||||
form.on_reply = (response) => {
|
|
||||||
const user = response.user;
|
|
||||||
APP.login( user );
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<div>
|
|
||||||
<input id="login-username" type="text" name="username" required />
|
|
||||||
<label class="placeholder" for="login-username">username</label>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input id="login-password" type="password" name="password" required />
|
|
||||||
<label class="placeholder" for="login-password">password</label>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button id="login-submit" type="submit" class="primary">Log In</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="signup-tab" class="tab">
|
<div id="signup-tab" class="tab">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
name="signup-login-tabs"
|
name="signup-login-tabs"
|
||||||
id="signup-tab-input"
|
id="signup-tab-input"
|
||||||
class="tab-switch"
|
class="tab-switch"
|
||||||
|
checked="checked"
|
||||||
/>
|
/>
|
||||||
<label for="signup-tab-input" class="tab-label">
|
<label for="signup-tab-input" class="tab-label">
|
||||||
<div class="label">Sign Up</div>
|
<div class="label">Sign Up</div>
|
||||||
|
|
@ -136,6 +113,7 @@
|
||||||
id="signup-invite-code"
|
id="signup-invite-code"
|
||||||
type="text"
|
type="text"
|
||||||
name="invite_code"
|
name="invite_code"
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
<label class="placeholder" for="signup-invite-code">invite code</label>
|
<label class="placeholder" for="signup-invite-code">invite code</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -143,6 +121,53 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="login-tab" class="tab">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="signup-login-tabs"
|
||||||
|
id="login-tab-input"
|
||||||
|
class="tab-switch"
|
||||||
|
/>
|
||||||
|
<label for="login-tab-input" class="tab-label">
|
||||||
|
<div class="label">Log In</div>
|
||||||
|
</label>
|
||||||
|
<div class="tab-content">
|
||||||
|
<form data-smart="true" data-method="POST" id="login-form" action="/api/auth">
|
||||||
|
<script>
|
||||||
|
{
|
||||||
|
const form = document.currentScript.closest("form");
|
||||||
|
form.on_reply = (response) => {
|
||||||
|
const user = response.user;
|
||||||
|
APP.login( user );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<div>
|
||||||
|
<input id="login-username" type="text" name="username" required />
|
||||||
|
<label class="placeholder" for="login-username">username</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input id="login-password" type="password" name="password" required />
|
||||||
|
<label class="placeholder" for="login-password">password</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button id="login-submit" type="submit" class="primary">Log In</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener( 'DOMContentLoaded', () => {
|
||||||
|
const authed_before = (document.cookie.match(
|
||||||
|
/^(?:.*;)?\s*authed_before\s*=\s*([^;]+)(?:.*)?$/,
|
||||||
|
) || [, null])[1];
|
||||||
|
|
||||||
|
if ( authed_before ) {
|
||||||
|
document.getElementById("login-tab-input").checked = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,6 @@
|
||||||
<div class="label">Calendar</div></label
|
<div class="label">Calendar</div></label
|
||||||
>
|
>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<!-- #include file="./README.md" -->
|
<!-- #include "./README.md" -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,6 @@
|
||||||
<div class="label">Exchange</div></label
|
<div class="label">Exchange</div></label
|
||||||
>
|
>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<!-- #include file="./README.md" -->
|
<!-- #include "./README.md" -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,6 @@
|
||||||
<div class="label">Home</div>
|
<div class="label">Home</div>
|
||||||
</label>
|
</label>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<!-- #include file="./README.md" -->
|
<!-- #include "./README.md" -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,5 @@
|
||||||
><div class="icon resources"></div>
|
><div class="icon resources"></div>
|
||||||
<div class="label">Resources</div></label
|
<div class="label">Resources</div></label
|
||||||
>
|
>
|
||||||
<div class="tab-content"><!-- #include file="./README.md" --></div>
|
<div class="tab-content"><!-- #include "./README.md" --></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -111,21 +111,13 @@
|
||||||
|
|
||||||
@media screen and (max-width: 800px) {
|
@media screen and (max-width: 800px) {
|
||||||
.tab-label {
|
.tab-label {
|
||||||
width: 3rem;
|
width: 4rem;
|
||||||
}
|
|
||||||
|
|
||||||
.tab-label .label {
|
|
||||||
font-size: small;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 400px) {
|
@media screen and (max-width: 400px) {
|
||||||
.tab-label {
|
.tab-label {
|
||||||
width: 2.5rem;
|
width: 3rem;
|
||||||
}
|
|
||||||
|
|
||||||
.tab-label .label {
|
|
||||||
font-size: 8px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,5 @@
|
||||||
><div class="icon work"></div>
|
><div class="icon work"></div>
|
||||||
<div class="label">Work</div>
|
<div class="label">Work</div>
|
||||||
</label>
|
</label>
|
||||||
<div class="tab-content"><!-- #include file="./README.md" --></div>
|
<div class="tab-content"><!-- #include "./README.md" --></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { EVENT } from '../models/event.ts';
|
||||||
export type PRECHECK = (req: Request, meta: Record<string, any>) => Promise<Response | undefined> | Response | undefined;
|
export type PRECHECK = (req: Request, meta: Record<string, any>) => Promise<Response | undefined> | Response | undefined;
|
||||||
export type PRECHECK_TABLE = Record<string, PRECHECK[]>;
|
export type PRECHECK_TABLE = Record<string, PRECHECK[]>;
|
||||||
|
|
||||||
|
export const AUTHED_BEFORE_COOKIE_ID: string = Deno.env.get('AUTHED_BEFORE_COOKIE_ID') ?? 'authed_before';
|
||||||
export const SESSION_ID_TOKEN: string = Deno.env.get('SESSION_ID_TOKEN') ?? 'session_id';
|
export const SESSION_ID_TOKEN: string = Deno.env.get('SESSION_ID_TOKEN') ?? 'session_id';
|
||||||
export const SESSION_SECRET_TOKEN: string = Deno.env.get('SESSION_SECRET_TOKEN') ?? 'session_secret';
|
export const SESSION_SECRET_TOKEN: string = Deno.env.get('SESSION_SECRET_TOKEN') ?? 'session_secret';
|
||||||
export const TOTP_TOKEN: string = Deno.env.get('TOTP_TOKEN') ?? 'totp';
|
export const TOTP_TOKEN: string = Deno.env.get('TOTP_TOKEN') ?? 'totp';
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue