a message doesn't cover this one. just read the code. it speaks for itself.
14
ERRORS.md
|
@ -6,20 +6,18 @@ All Burger-based software uses a simple logging system that outputs to TTY. Log
|
|||
|
||||
A log entry looks something like this:
|
||||
|
||||
| DATE | HUMAN-READABLE TIME | LOGLEVEL | DESCRIPTION | UNIX TIME* |
|
||||
| DATE | HUMAN-READABLE TIME | LOGLEVEL | DESCRIPTION |
|
||||
|---|---|---|---|---|
|
||||
| 1969/12/31 | 11:59:59 | [INFO] | Added a new user at | 0000000000 |
|
||||
|
||||
*Unix time is only supplied once the server starts. The "Welcome" log that is outputted at the beginning of the program does not contain a timestamp (E.G `1970/12/31 00:00:00 [INFO] Welcome to Burgernotes! Today we are running on IP 0.0.0.0 on port 8080.`)
|
||||
| 1969/12/31 | 11:59:59 | [INFO] | Added a new user |
|
||||
|
||||
## Log levels
|
||||
|
||||
There are 5 different log levels, with differing amounts of urgency
|
||||
|
||||
| INFO | WARN | ERROR | CRITICAL | FATAL | PROMPT |
|
||||
|---|---|---|---|---|---|
|
||||
| Usually harmless infomation, like a user being created | A warning about bad practices being used, such as having an unset config option | An error that disrupts user experience and may lead to undesired client-side behaviour | An error that affects all users on the platform | An error critical enough to warrent crashing the server process, usually something like the server being unable to bind to an IP or not being able to create the database | Anything that asks the user for input, like a confirmation dialog (typically has no timestamp) |
|
||||
| INFO | WARN | ERROR | CRITICAL | FATAL | PROMPT |
|
||||
|---------------------------------------------------------|---------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|-------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|
|
||||
| Usually harmless information, like a user being created | A warning about bad practices being used, such as having an unset config option | An error that disrupts user experience and may lead to undesired client-side behaviour | An error that affects all users on the platform | An error critical enough to warrant crashing the server process, usually something like the server being unable to bind to an IP or not being able to create the database | Anything that asks the user for input, like a confirmation dialog (typically has no timestamp) |
|
||||
|
||||
## Error reporting
|
||||
|
||||
Clients will be given 500 status code and an error code if any errors were to affect them. They are told to come to this page for more infomation. If you are one such client, please go to the issues tab and paste the error code along with some context, so we can fix the bug.
|
||||
Clients will be given 500 status code and an error code if any errors were to affect them. They are told to come to this page for more information. If you are one such client, please go to the issues tab and paste the error code along with some context, so we can fix the bug.
|
|
@ -11,8 +11,11 @@ PRIVATE_KEY = keys/private.pem
|
|||
# This is the URI to the privacy policy. Leave as default to use the default burgerauth policy.
|
||||
PRIVACY_POLICY = https://concord.hectabit.org/Paperwork/Burgerauth/src/commit/3a58ec33ead87aadd542c5838b3162ed6cedc044/Privacy.md
|
||||
# This is the URL the server is running on. Change this to your URL. This must be the URL in front of your reverse-proxy, and should not be an IP as to enforce HTTPS.
|
||||
URL = https://auth.hectabit.org
|
||||
URL = https://example.org
|
||||
# This is the name of the program you wish users to see.
|
||||
IDENTIFIER = Burgerauth
|
||||
# This is the identifier for your key in JWK. It is ok to set it to a random string of characters.
|
||||
KEY_ID = burgerauth
|
||||
# Serious mode disables marketing, fancy HTML front-pages, easter eggs and basically everything that does not belong in a professional environment. I recommend enabling this if you want to self-host an instance.
|
||||
SERIOUS_MODE = false
|
||||
# The mode does not affect the API or functionality, only changing a couple appearances and logs.
|
4
go.mod
|
@ -3,7 +3,7 @@ module hectabit.org/burgerauth
|
|||
go 1.22
|
||||
|
||||
require (
|
||||
concord.hectabit.org/HectaBit/captcha v1.4.5
|
||||
github.com/catalinc/hashcash v1.0.0
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/gin-contrib/sessions v1.0.1
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
|
@ -23,7 +23,6 @@ require (
|
|||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.19.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/gorilla/context v1.1.2 // indirect
|
||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||
github.com/gorilla/sessions v1.2.2 // indirect
|
||||
|
@ -50,7 +49,6 @@ require (
|
|||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/arch v0.7.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/image v0.15.0 // indirect
|
||||
golang.org/x/net v0.24.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
|
|
8
go.sum
|
@ -1,9 +1,9 @@
|
|||
concord.hectabit.org/HectaBit/captcha v1.4.5 h1:kMqT0ZUPb/YZr1VDw9L1Dqpe/hzy3Cw7QhCahW6PNdM=
|
||||
concord.hectabit.org/HectaBit/captcha v1.4.5/go.mod h1:PaJDe3Nrjl2WZOYmkYpefwJ9dMP+BvV+M1VWot4/I04=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||
github.com/bytedance/sonic v1.11.3 h1:jRN+yEjakWh8aK5FzrciUHG8OFXK+4/KrAX/ysEtHAA=
|
||||
github.com/bytedance/sonic v1.11.3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||
github.com/catalinc/hashcash v1.0.0 h1:DiI2kBNCczy7y3xJnLddIl7KGx0yP4B7irFZZ+yzzwc=
|
||||
github.com/catalinc/hashcash v1.0.0/go.mod h1:ldWL6buwYCK4VqIkLbZuFbGUoJceSafm8duCEQYw9Jw=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
|
||||
|
@ -39,8 +39,6 @@ github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn
|
|||
github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
|
@ -129,8 +127,6 @@ golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
|||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
||||
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
11
schema.sql
|
@ -9,7 +9,8 @@ CREATE TABLE users (
|
|||
created TEXT NOT NULL,
|
||||
username TEXT NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
uniqueid TEXT NOT NULL
|
||||
uniqueid TEXT NOT NULL,
|
||||
migrated INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE userdata (
|
||||
|
@ -32,9 +33,11 @@ CREATE TABLE blacklist (
|
|||
);
|
||||
|
||||
CREATE TABLE oauth (
|
||||
appId TEXT NOT NULL,
|
||||
appId TEXT NOT NULL UNIQUE,
|
||||
secret TEXT NOT NULL,
|
||||
creator INTEGER NOT NULL,
|
||||
rdiruri TEXT NOT NULL,
|
||||
name TEXT NOT NULL
|
||||
redirectUri TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
keyShareUri TEXT NOT NULL DEFAULT 'none',
|
||||
scopes TEXT NOT NULL DEFAULT '["openid"]'
|
||||
)
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
--invertdm: 0%;
|
||||
--text-color: #000000;
|
||||
--editor: #ffffff;
|
||||
--bar: #f4f4f4;
|
||||
--border-color: #dadada;
|
||||
--theme-color: #157efb;
|
||||
--theme-color: #1c71d8;
|
||||
--hover-theme-color: #4990e7;
|
||||
--nonimporant-theme-color: #4A4A4A;
|
||||
--hover-nonimportant-theme-color: #595959;
|
||||
--nonimporant-theme-color: #EBEBEB;
|
||||
--hover-nonimportant-theme-color: #dbdbdb;
|
||||
--nonimportant-text-color: #000;
|
||||
--inoutdiv: #fafafa;
|
||||
}
|
||||
|
||||
/* dark mode */
|
||||
|
@ -17,9 +18,10 @@
|
|||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--invertdm: 100%;
|
||||
--bar: #2d2f31;
|
||||
--inoutdiv: #2d2f31;
|
||||
--text-color: #ffffff;
|
||||
--editor: #1E1E1E;
|
||||
--nonimportant-text-color: #fff;
|
||||
--border-color: #393b3d;
|
||||
}
|
||||
|
||||
|
@ -49,6 +51,10 @@ h6 {
|
|||
white-space: break-spaces;
|
||||
}
|
||||
|
||||
p#status {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: var(--editor);
|
||||
|
@ -62,13 +68,18 @@ body {
|
|||
margin: 10%;
|
||||
padding: 30px;
|
||||
border: solid 1px var(--border-color);
|
||||
background-color: var(--bar);
|
||||
background-color: var(--inoutdiv);
|
||||
}
|
||||
|
||||
table {
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
input {
|
||||
width: calc(100% - 120px);
|
||||
width: calc(100% - 35px);
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
height: 30px;
|
||||
margin-bottom: 10px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
|
||||
|
@ -79,17 +90,22 @@ input {
|
|||
min-width: 20px;
|
||||
}
|
||||
|
||||
.inputBox input {
|
||||
margin-left: 5px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
body {
|
||||
background-color: var(--bar);
|
||||
background-color: var(--inoutdiv);
|
||||
}
|
||||
.inoutdiv {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
border-radius: 0;
|
||||
min-width: 100%;
|
||||
min-width: calc(100% - 20px);
|
||||
min-height: 100%;
|
||||
transform: none;
|
||||
padding: 5px;
|
||||
|
@ -112,16 +128,6 @@ input {
|
|||
}
|
||||
}
|
||||
|
||||
.inoutdiv button {
|
||||
color: white;
|
||||
margin-right: 5px;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 25px;
|
||||
font-size: 14px;
|
||||
transition: 0.125s;
|
||||
}
|
||||
|
||||
.inoutdiv img {
|
||||
min-width: 200px;
|
||||
max-width: 100%;
|
||||
|
@ -134,7 +140,7 @@ input {
|
|||
right: 5px;
|
||||
top: 47px;
|
||||
border: none;
|
||||
height: 276px;
|
||||
height: 278px;
|
||||
width: 400px;
|
||||
transform: translateX(26px);
|
||||
}
|
||||
|
@ -159,7 +165,7 @@ input {
|
|||
text-shadow: black 1px 1px 5px;
|
||||
}
|
||||
|
||||
.newoauth, .oauthlist, .oauthentry {
|
||||
.newoauth, .oauthlist, .sessionentry, .oauthentry {
|
||||
text-align: center;
|
||||
width: calc(100% - 17.5vh);
|
||||
margin-top: 7vh;
|
||||
|
@ -171,35 +177,43 @@ input {
|
|||
border-radius: 8px;
|
||||
border-width: 1px;
|
||||
font-size: 17px;
|
||||
background-color: var(--bar);
|
||||
background-color: var(--inoutdiv);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
.oauthentry {
|
||||
.oauthentry, .sessionentry {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 5px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.oauthentry button {
|
||||
.oauthentry button, .sessionentry button {
|
||||
padding: 10px;
|
||||
background-color: red;
|
||||
color: white
|
||||
}
|
||||
|
||||
.oauthentry button:hover {
|
||||
.oauthentry button:hover, .sessionentry button:hover {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.oauthentry img, .sessionentry img {
|
||||
max-height: 64px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: var(--theme-color);
|
||||
color: white;
|
||||
padding: 10px;
|
||||
margin-right: 5px;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
border-radius: 25px;
|
||||
font-size: 14px;
|
||||
transition: 0.125s;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
|
@ -207,8 +221,20 @@ button:hover {
|
|||
transition: all 0.3s ease 0s;
|
||||
}
|
||||
|
||||
.inoutdiv .inputContainer {
|
||||
margin-bottom: 20px;
|
||||
margin-right: 20px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.inoutdiv .inputBox {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.unimportant {
|
||||
var(--nonimporant-theme-color);
|
||||
background-color: var(--nonimporant-theme-color);
|
||||
color: var(--nonimportant-text-color) !important;
|
||||
}
|
||||
|
||||
.unimportant:hover {
|
||||
|
@ -242,6 +268,12 @@ h2 {
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
.vAlign {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
|
|
@ -1 +1,109 @@
|
|||
// To be implemented in the future
|
||||
async function main() {
|
||||
try {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const token = urlParams.get('token');
|
||||
if (!token) {
|
||||
document.getElementById("errors").innerText = "No token was provided. Redirecting to dashboard...";
|
||||
setTimeout(() => {
|
||||
window.location.replace("/dashboard");
|
||||
}, 3000);
|
||||
} else {
|
||||
const response = await fetch("/api/aeskeyshare", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
access_token: token
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
});
|
||||
if (response.status === 200) {
|
||||
let responseData = await response.json();
|
||||
const publicKeyParam = urlParams.get('pubkey');
|
||||
if (!publicKeyParam) {
|
||||
document.getElementById("errors").innerText = "The website you were visiting has not provided a public key. Encryption cannot proceed. Redirecting to dashboard...";
|
||||
setTimeout(() => {
|
||||
window.location.replace("/dashboard");
|
||||
}, 3000);
|
||||
} else {
|
||||
const publicKeyBytes = atob(publicKeyParam.replace(/_/g, '/').replace(/~/g, '+'));
|
||||
const publicKeyBuffer = new Uint8Array(publicKeyBytes.length);
|
||||
for (let i = 0; i < publicKeyBytes.length; i++) {
|
||||
publicKeyBuffer[i] = publicKeyBytes.charCodeAt(i);
|
||||
}
|
||||
let publicKey;
|
||||
try {
|
||||
publicKey = await window.crypto.subtle.importKey(
|
||||
"spki",
|
||||
publicKeyBuffer,
|
||||
{
|
||||
name: "RSA-OAEP",
|
||||
hash: {name: "SHA-512"}
|
||||
},
|
||||
true,
|
||||
["encrypt"]
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error:', error.message);
|
||||
document.getElementById("errors").innerText = "The public key provided by the website is invalid. Encryption cannot proceed. Redirecting to dashboard...";
|
||||
setTimeout(() => {
|
||||
window.location.replace("/dashboard");
|
||||
}, 3000);
|
||||
return
|
||||
}
|
||||
document.getElementById("errors").innerText = "Generating encryption keys...";
|
||||
const message = await hashwasm.argon2id({
|
||||
password: localStorage.getItem("DONOTSHARE-password") + responseData["appId"],
|
||||
salt: new TextEncoder().encode("Burgers are yum!"),
|
||||
parallelism: 1,
|
||||
iterations: 32,
|
||||
memorySize: 19264,
|
||||
hashLength: 32,
|
||||
outputType: "hex"
|
||||
});
|
||||
document.getElementById("errors").innerText = "Encrypting message...";
|
||||
const encryptedMessageBuffer = await window.crypto.subtle.encrypt(
|
||||
{
|
||||
name: "RSA-OAEP"
|
||||
},
|
||||
publicKey,
|
||||
new TextEncoder().encode(message)
|
||||
);
|
||||
const encodedMessage = btoa(String.fromCharCode.apply(null, new Uint8Array(encryptedMessageBuffer))).replace(/\+/g, '~').replace(/\//g, '_').replace(/=+$/, '');
|
||||
window.location.replace(responseData["keyShareUri"] + "/?encoded=" + encodedMessage)
|
||||
}
|
||||
} else if (response.status === 401) {
|
||||
const responseData = await response.json();
|
||||
document.getElementById("errors").innerText = "The token provided is invalid: " + responseData["error"] + " Redirecting to dashboard...";
|
||||
setTimeout(() => {
|
||||
window.location.replace("/dashboard");
|
||||
}, 3000);
|
||||
} else if (response.status === 500) {
|
||||
const responseData = await response.json();
|
||||
document.getElementById("errors").innerText = responseData["error"];
|
||||
setTimeout(() => {
|
||||
window.location.replace("/dashboard");
|
||||
}, 3000);
|
||||
} else if (response.status === 403) {
|
||||
document.getElementById("errors").innerText = "The token provided has expired. Redirecting to dashboard...";
|
||||
setTimeout(() => {
|
||||
window.location.replace("/dashboard");
|
||||
}, 3000);
|
||||
} else {
|
||||
const responseData = await response.json();
|
||||
document.getElementById("errors").innerText = "An unknown error occurred: " + responseData["error"] + " Redirecting to dashboard...";
|
||||
setTimeout(() => {
|
||||
window.location.replace("/dashboard");
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error.message);
|
||||
document.getElementById("errors").innerText = "An error occurred and was logged to the console. Redirecting to dashboard...";
|
||||
setTimeout(() => {
|
||||
window.location.replace("/dashboard");
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = main;
|
|
@ -3,15 +3,20 @@ if (localStorage.getItem("DONOTSHARE-secretkey") === null) {
|
|||
document.body.innerHTML = "Redirecting..."
|
||||
throw new Error();
|
||||
}
|
||||
let remote = localStorage.getItem("homeserverURL")
|
||||
if (remote == null) {
|
||||
localStorage.setItem("homeserverURL", "https://auth.hectabit.org")
|
||||
remote = "https://auth.hectabit.org"
|
||||
}
|
||||
|
||||
|
||||
function attempt() {
|
||||
if (document.getElementById("appidbox").value !== "") {
|
||||
let openid = false;
|
||||
if (document.getElementById("openidbox").checked) {
|
||||
openid = true
|
||||
}
|
||||
let scopes = []
|
||||
if (openid) {
|
||||
scopes.push("openid")
|
||||
}
|
||||
if (document.getElementById("aeskeysharebox").value !== "") {
|
||||
scopes.push("aeskeyshare")
|
||||
}
|
||||
fetch(origin + "/api/newauth", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
@ -19,29 +24,114 @@ function attempt() {
|
|||
},
|
||||
body: JSON.stringify({
|
||||
name: document.getElementById("appidbox").value,
|
||||
rdiruri: document.getElementById("rdiruribox").value,
|
||||
secretKey: localStorage.getItem("DONOTSHARE-secretkey")
|
||||
redirectUri: document.getElementById("rdiruribox").value,
|
||||
secretKey: localStorage.getItem("DONOTSHARE-secretkey"),
|
||||
scopes: JSON.stringify(scopes),
|
||||
keyShareUri: document.getElementById("aeskeysharebox").value
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
async function doStuff() {
|
||||
let code = await response.json()
|
||||
if (response.status === 200) {
|
||||
document.getElementById("status").innerText = "Your secret key is: " + code["key"] + " and your client id is: " + code["appId"] + ". This will only be shown once!"
|
||||
getauths();
|
||||
} else if (response.status === 500) {
|
||||
document.getElementById("status").innerText = "Whoops... Something went wrong. Please try again later. (Error Code 500)"
|
||||
} else if (response.status === 401) {
|
||||
document.getElementById("status").innerText = "AppID already taken. (Error Code 401)"
|
||||
} else {
|
||||
document.getElementById("status").innerText = "Unkown error encountered. (Error Code " + response.status + ")"
|
||||
}
|
||||
.then(async response => {
|
||||
let code = await response.json()
|
||||
document.getElementById("appidbox").value = ""
|
||||
document.getElementById("rdiruribox").value = ""
|
||||
document.getElementById("aeskeysharebox").value = ""
|
||||
document.getElementById("openidbox").checked = false
|
||||
if (response.status === 200) {
|
||||
document.getElementById("status").innerText = "Your secret key is: " + code["key"] + " and your client id is: " + code["appId"] + ". This will only be shown once!"
|
||||
getauths();
|
||||
} else if (response.status === 500) {
|
||||
document.getElementById("status").innerText = code["error"]
|
||||
} else if (response.status === 401) {
|
||||
document.getElementById("status").innerText = "AppID already taken. (Error Code: " + code["error"] + ")"
|
||||
} else {
|
||||
document.getElementById("status").innerText = "Unknown error encountered. (Error Code:" + code["error"] + ")"
|
||||
}
|
||||
doStuff()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function getSessions() {
|
||||
fetch(origin + "/api/sessions/list", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
secretKey: localStorage.getItem("DONOTSHARE-secretkey")
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
.then(async (response) => {
|
||||
let responseData = await response.json()
|
||||
if (response.status === 200) {
|
||||
if (responseData === null || responseData.length === 0) {
|
||||
let statusText = document.createElement("p")
|
||||
statusText.classList.add("sessionInfo")
|
||||
statusText.innerText = "Hi there! You don't have any sessions logged in, somehow. Congratulations on breaking the laws of physics!"
|
||||
document.getElementById("sessionsList").append(statusText)
|
||||
} else {
|
||||
document.querySelectorAll(".sessionInfo").forEach(e => e.remove())
|
||||
document.querySelectorAll(".sessionentry").forEach(e => e.remove())
|
||||
for (let i in responseData) {
|
||||
let sessionElement = document.createElement("div")
|
||||
let sessionDevice = document.createElement("p")
|
||||
let sessionRemoveButton = document.createElement("button")
|
||||
let sessionImage = document.createElement("img")
|
||||
if (responseData[i]["thisSession"]) {
|
||||
sessionDevice.innerText = "(current) " + responseData[i]["device"]
|
||||
} else {
|
||||
sessionDevice.innerText = responseData[i]["device"]
|
||||
}
|
||||
|
||||
if (responseData[i]["device"].includes("NT") || responseData[i]["device"].includes("Linux") || responseData[i]["device"].includes("Macintosh")) {
|
||||
sessionImage.src = "/static/svg/device_computer.svg"
|
||||
} else if (responseData[i]["device"].includes("iPhone" || responseData[i]["device"].includes("Android") || responseData[i]["device"].includes("iPod"))) {
|
||||
sessionImage.src = "/static/svg/device_smartphone.svg"
|
||||
} else if (responseData[i]["device"].includes("curl")) {
|
||||
sessionImage.src = "/static/svg/device_terminal.svg"
|
||||
} else {
|
||||
sessionImage.src = "/static/svg/device_other.svg"
|
||||
}
|
||||
|
||||
sessionRemoveButton.innerText = "Remove session"
|
||||
sessionRemoveButton.addEventListener("click", () => {
|
||||
fetch(origin + "/api/deleteauth", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
secretKey: localStorage.getItem("DONOTSHARE-secretkey"),
|
||||
appId: responseData[i]["appId"]
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
sessionElement.remove()
|
||||
if (responseData[i]["thisSession"]) {
|
||||
window.location.replace("/logout")
|
||||
}
|
||||
});
|
||||
|
||||
sessionElement.append(sessionImage)
|
||||
sessionElement.append(sessionDevice)
|
||||
sessionElement.append(sessionRemoveButton)
|
||||
sessionElement.classList.add("sessionentry")
|
||||
|
||||
document.getElementById("sessionsList").append(sessionElement)
|
||||
}
|
||||
}
|
||||
} else if (response.status === 500) {
|
||||
let statusText = document.createElement("p")
|
||||
statusText.classList.add("sessionInfo")
|
||||
statusText.innerText = responseData["error"]
|
||||
document.getElementById("sessionsList").append(statusText)
|
||||
} else {
|
||||
let statusText = document.createElement("p")
|
||||
statusText.classList.add("sessionInfo")
|
||||
statusText.innerText = "Something went wrong! (error code: " + responseData["error"] + ")"
|
||||
document.getElementById("sessionsList").append(statusText)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getauths() {
|
||||
fetch(origin + "/api/listauth", {
|
||||
method: "POST",
|
||||
|
@ -52,47 +142,174 @@ function getauths() {
|
|||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
async function doStuff() {
|
||||
let responseData = await response.json()
|
||||
document.querySelectorAll(".oauthentry").forEach((el) => el.remove());
|
||||
for (let i in responseData) {
|
||||
let oauthElement = document.createElement("div")
|
||||
let oauthText = document.createElement("p")
|
||||
let oauthName = document.createElement("p")
|
||||
let oauthUrl = document.createElement("p")
|
||||
let oauthRemoveButton = document.createElement("button")
|
||||
oauthText.innerText = "Client ID: " + responseData[i]["appId"]
|
||||
oauthName.innerText = "App name: " + responseData[i]["name"]
|
||||
oauthUrl.innerText = "Redirect Url: " + responseData[i]["rdiruri"]
|
||||
oauthRemoveButton.innerText = "Delete Permanently"
|
||||
oauthRemoveButton.addEventListener("click", () => {
|
||||
if (window.confirm("Are you SURE you would like to delete this FOREVER?") === true) {
|
||||
fetch(origin + "/api/deleteauth", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
secretKey: localStorage.getItem("DONOTSHARE-secretkey"),
|
||||
appId: responseData[i]["appId"]
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
.then(async (response) => {
|
||||
let responseData = await response.json()
|
||||
if (response.status === 200) {
|
||||
if (responseData === null || responseData.length === 0) {
|
||||
let statusText = document.createElement("p")
|
||||
statusText.classList.add("authInfo")
|
||||
statusText.innerText = "Hi there! You don't have any OAuth2 clients yet. Create one above!"
|
||||
document.getElementById("oauthlist").append(statusText)
|
||||
} else {
|
||||
document.querySelectorAll(".authInfo").forEach(e => e.remove())
|
||||
document.querySelectorAll(".oauthentry").forEach(e => e.remove())
|
||||
for (let i in responseData) {
|
||||
let oauthElement = document.createElement("div")
|
||||
let oauthText = document.createElement("p")
|
||||
let oauthName = document.createElement("p")
|
||||
let oauthUrl = document.createElement("p")
|
||||
let oauthRemoveButton = document.createElement("button")
|
||||
oauthText.innerText = "Client ID: " + responseData[i]["appId"]
|
||||
oauthName.innerText = "App name: " + responseData[i]["name"]
|
||||
oauthUrl.innerText = "Redirect Url: " + responseData[i]["redirectUri"]
|
||||
oauthRemoveButton.innerText = "Delete Permanently"
|
||||
oauthRemoveButton.addEventListener("click", () => {
|
||||
if (window.confirm("Are you SURE you would like to delete this FOREVER?") === true) {
|
||||
fetch(origin + "/api/deleteauth", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
secretKey: localStorage.getItem("DONOTSHARE-secretkey"),
|
||||
appId: responseData[i]["appId"]
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
oauthElement.remove()
|
||||
}
|
||||
});
|
||||
|
||||
oauthElement.append(oauthText)
|
||||
oauthElement.append(oauthName)
|
||||
oauthElement.append(oauthUrl)
|
||||
|
||||
let openid = false
|
||||
let aesKeyShare = false
|
||||
let scopes = JSON.parse(responseData[i]["scopes"])
|
||||
for (let n in scopes) {
|
||||
console.log(scopes[n])
|
||||
if (scopes[n] === "openid") {
|
||||
openid = true
|
||||
} else if (scopes[n] === "aeskeyshare") {
|
||||
if (responseData[i]["keyShareUri"] !== "none") {
|
||||
aesKeyShare = true
|
||||
let keyShareUri = document.createElement("p")
|
||||
keyShareUri.innerText = "Key Share URI: " + responseData[i]["keyShareUri"]
|
||||
oauthElement.append(keyShareUri)
|
||||
}
|
||||
})
|
||||
oauthElement.remove()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
oauthElement.append(oauthText)
|
||||
oauthElement.append(oauthName)
|
||||
oauthElement.append(oauthUrl)
|
||||
oauthElement.append(oauthRemoveButton)
|
||||
oauthElement.classList.add("oauthentry")
|
||||
let scopeTxt = document.createElement("p")
|
||||
if (openid || aesKeyShare) {
|
||||
scopeTxt.innerText = "Scopes: "
|
||||
if (openid) {
|
||||
scopeTxt.innerText += "openid"
|
||||
}
|
||||
if (aesKeyShare) {
|
||||
if (!openid) {
|
||||
scopeTxt.innerText += "aeskeyshare"
|
||||
} else {
|
||||
scopeTxt.innerText += ", aeskeyshare"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
scopeTxt.innerText = "You have not defined any scopes for this client."
|
||||
}
|
||||
|
||||
document.getElementById("oauthlist").append(oauthElement)
|
||||
oauthElement.append(scopeTxt)
|
||||
oauthElement.append(oauthRemoveButton)
|
||||
oauthElement.classList.add("oauthentry")
|
||||
|
||||
document.getElementById("oauthlist").append(oauthElement)
|
||||
}
|
||||
}
|
||||
} else if (response.status === 500) {
|
||||
let statusText = document.createElement("p")
|
||||
statusText.classList.add("authInfo")
|
||||
statusText.innerText = responseData["error"]
|
||||
document.getElementById("oauthlist").append(statusText)
|
||||
} else {
|
||||
let statusText = document.createElement("p")
|
||||
statusText.classList.add("authInfo")
|
||||
statusText.innerText = "Something went wrong! (error code: " + responseData["error"] + ")"
|
||||
document.getElementById("oauthlist").append(statusText)
|
||||
}
|
||||
doStuff()
|
||||
});
|
||||
}
|
||||
|
||||
getauths()
|
||||
async function checkNetwork() {
|
||||
let loggedIn = await fetch("/api/secretkeyloggedin", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
secretKey: localStorage.getItem("DONOTSHARE-secretkey")
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
if (loggedIn.status === 200) {
|
||||
return true
|
||||
} else {
|
||||
localStorage.removeItem("DONOTSHARE-secretkey");
|
||||
localStorage.removeItem("DONOTSHARE-password");
|
||||
window.location.replace("/login" + window.location.search);
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteacct() {
|
||||
if (confirm("Are you SURE you would like to delete your account forever?") === true) {
|
||||
await fetch("/api/deleteaccount", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
"secretKey": localStorage.getItem("DONOTSHARE-secretkey")
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
.then((response) => response)
|
||||
.then((response) => {
|
||||
async function doStuff() {
|
||||
if (response.status === 200) {
|
||||
parent.window.location.href = '/logout';
|
||||
}
|
||||
}
|
||||
doStuff()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
checkNetwork().then(async (result) => {
|
||||
if (result) {
|
||||
getauths()
|
||||
getSessions()
|
||||
let response = await fetch("/api/userinfo", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
"secretKey": localStorage.getItem("DONOTSHARE-secretkey")
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
const data = await response.json()
|
||||
if (response.status === 200) {
|
||||
document.getElementById("namebox").innerText = "Username: " + data["username"];
|
||||
document.getElementById("datebox").innerText = "Account created: " + new Date(data["created"] * 1000).toLocaleString();
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
document.getElementById("devAcctSwitcher").addEventListener("click", () => {
|
||||
document.getElementById("developers").classList.toggle("hidden")
|
||||
document.getElementById("account").classList.toggle("hidden")
|
||||
if (document.getElementById("devAcctSwitcher").innerText === "Switch to developer view") {
|
||||
document.getElementById("devAcctSwitcher").innerText = "Switch to account view"
|
||||
} else {
|
||||
document.getElementById("devAcctSwitcher").innerText = "Switch to developer view"
|
||||
}
|
||||
})
|
|
@ -0,0 +1,30 @@
|
|||
async function main() {
|
||||
const response = await fetch("/api/aeskeyshare", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
access_token: urlParams.get('token')
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
});
|
||||
if (response.status === 200) {
|
||||
let responseData = await response.json();
|
||||
const message = await hashwasm.argon2id({
|
||||
password: localStorage.getItem("DONOTSHARE-password") + responseData["appId"],
|
||||
salt: new TextEncoder().encode("Burgers are yum!"),
|
||||
parallelism: 1,
|
||||
iterations: 32,
|
||||
memorySize: 19264,
|
||||
hashLength: 32,
|
||||
outputType: "hex"
|
||||
});
|
||||
window.postMessage("finished", "*");
|
||||
console.log("finished")
|
||||
localStorage.setItem("DONOTSHARE-EXCHANGED-KEY", responseData[message]);
|
||||
} else {
|
||||
console.error("Error:", response.status);
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = main;
|
|
@ -0,0 +1,77 @@
|
|||
function saveArrayBufferToLocalStorage(key, buffer) {
|
||||
const base64String = arrayBufferToBase64(buffer);
|
||||
localStorage.setItem(key, base64String);
|
||||
}
|
||||
|
||||
function getArrayBufferFromLocalStorage(key) {
|
||||
const base64String = localStorage.getItem(key);
|
||||
if (base64String) {
|
||||
return base64ToArrayBuffer(base64String);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function arrayBufferToBase64(buffer) {
|
||||
const uint8Array = new Uint8Array(buffer);
|
||||
return btoa(String.fromCharCode.apply(null, uint8Array)).replace(/\+/g, '~').replace(/\//g, '_').replace(/=+$/, '');
|
||||
}
|
||||
|
||||
function base64ToArrayBuffer(base64) {
|
||||
const binaryString = atob(base64.replace(/_/g, '/').replace(/~/g, '+'));
|
||||
const length = binaryString.length;
|
||||
const buffer = new ArrayBuffer(length);
|
||||
const uint8Array = new Uint8Array(buffer);
|
||||
for (let i = 0; i < length; i++) {
|
||||
uint8Array[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function generateKeyPair() {
|
||||
return window.crypto.subtle.generateKey(
|
||||
{
|
||||
name: "RSA-OAEP",
|
||||
modulusLength: 4096,
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
||||
hash: {name: "SHA-512"}
|
||||
},
|
||||
true,
|
||||
["encrypt", "decrypt"]
|
||||
);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const encodedData = urlParams.get('encoded');
|
||||
const doNothing = urlParams.get('donothing');
|
||||
let keyShareUri = "https://auth.hectabit.org/aeskeyshare"
|
||||
if (localStorage.getItem("keyShareUri") !== null) {
|
||||
keyShareUri = localStorage.getItem("keyShareUri")
|
||||
}
|
||||
if (localStorage.getItem("referrer") === null) {
|
||||
return
|
||||
}
|
||||
if (doNothing !== "true") {
|
||||
if (encodedData) {
|
||||
const decodedData = base64ToArrayBuffer(encodedData);
|
||||
const decryptedData = window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: "RSA-OAEP"
|
||||
},
|
||||
await crypto.subtle.importKey("pkcs8", getArrayBufferFromLocalStorage("key"), {
|
||||
name: "RSA-OAEP",
|
||||
hash: {name: "SHA-512"}
|
||||
}, true, ["decrypt"]),
|
||||
decodedData
|
||||
);
|
||||
localStorage.setItem("DONOTSHARE-EXCHANGED-KEY", new TextDecoder().decode(await decryptedData));
|
||||
window.location.replace(localStorage.getItem("referrer"))
|
||||
} else {
|
||||
let keyPair = await generateKeyPair();
|
||||
saveArrayBufferToLocalStorage("key", await crypto.subtle.exportKey("pkcs8", keyPair.privateKey));
|
||||
window.location.replace(keyShareUri + "?pubkey=" + btoa(String.fromCharCode.apply(null, new Uint8Array(await crypto.subtle.exportKey("spki", keyPair.publicKey)))).replace(/\+/g, '~').replace(/\//g, '_').replace(/=+$/, '') + "&token=" + localStorage.getItem("BURGERAUTH-RDIR-TOKEN"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = main;
|
|
@ -12,9 +12,11 @@ if (localStorage.getItem("DONOTSHARE-password") !== null) {
|
|||
let usernameBox = document.getElementById("usernameBox")
|
||||
let passwordBox = document.getElementById("passwordBox")
|
||||
let statusBox = document.getElementById("statusBox")
|
||||
let nextButton = document.getElementById("nextButton")
|
||||
let signupButton = document.getElementById("signupButton")
|
||||
let inputNameBox = document.getElementById("inputNameBox")
|
||||
let backButton = document.getElementById("backButton")
|
||||
let inputContainer = document.getElementById("inputContainer")
|
||||
|
||||
usernameBox.classList.remove("hidden")
|
||||
inputNameBox.innerText = "Username:"
|
||||
|
@ -23,7 +25,9 @@ let currentInputType = 0
|
|||
|
||||
function showInput(inputType) {
|
||||
if (inputType === 0) {
|
||||
inputContainer.classList.remove("hidden")
|
||||
usernameBox.classList.remove("hidden")
|
||||
signupButton.classList.remove("hidden")
|
||||
passwordBox.classList.add("hidden")
|
||||
backButton.classList.add("hidden")
|
||||
inputNameBox.innerText = "Username:"
|
||||
|
@ -36,18 +40,19 @@ function showInput(inputType) {
|
|||
currentInputType = 0
|
||||
})
|
||||
} else if (inputType === 1) {
|
||||
inputContainer.classList.remove("hidden")
|
||||
signupButton.classList.add("hidden")
|
||||
usernameBox.classList.add("hidden")
|
||||
passwordBox.classList.remove("hidden")
|
||||
backButton.classList.remove("hidden")
|
||||
inputNameBox.innerText = "Password:"
|
||||
currentInputType = 1
|
||||
} else if (inputType === 2) {
|
||||
usernameBox.classList.add("hidden")
|
||||
passwordBox.classList.add("hidden")
|
||||
signupButton.classList.add("hidden")
|
||||
nextButton.classList.add("hidden")
|
||||
backButton.classList.add("hidden")
|
||||
inputContainer.classList.add("hidden")
|
||||
inputNameBox.classList.add("hidden")
|
||||
inputNameBox.innerText = "Password:"
|
||||
currentInputType = 2
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +61,7 @@ function showElements(yesorno) {
|
|||
if (!yesorno) {
|
||||
usernameBox.classList.add("hidden")
|
||||
passwordBox.classList.add("hidden")
|
||||
signupButton.classList.add("hidden")
|
||||
nextButton.classList.add("hidden")
|
||||
backButton.classList.add("hidden")
|
||||
inputNameBox.classList.add("hidden")
|
||||
showInput(currentInputType)
|
||||
|
@ -64,18 +69,14 @@ function showElements(yesorno) {
|
|||
else {
|
||||
usernameBox.classList.remove("hidden")
|
||||
passwordBox.classList.remove("hidden")
|
||||
signupButton.classList.remove("hidden")
|
||||
nextButton.classList.remove("hidden")
|
||||
backButton.classList.remove("hidden")
|
||||
inputNameBox.classList.remove("hidden")
|
||||
showInput(currentInputType)
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.getElementById("homeserver").innerText = "Your homeserver is: " + remote + ". "
|
||||
});
|
||||
|
||||
signupButton.addEventListener("click", () => {
|
||||
nextButton.addEventListener("click", async () => {
|
||||
if (passwordBox.classList.contains("hidden")) {
|
||||
if (usernameBox.value === "") {
|
||||
statusBox.innerText = "A username is required!"
|
||||
|
@ -85,65 +86,141 @@ signupButton.addEventListener("click", () => {
|
|||
}
|
||||
showInput(1)
|
||||
} else {
|
||||
async function doStuff() {
|
||||
let username = usernameBox.value
|
||||
let password = passwordBox.value
|
||||
let username = usernameBox.value
|
||||
let password = passwordBox.value
|
||||
|
||||
if (password === "") {
|
||||
statusBox.innerText = "A password is required!"
|
||||
return
|
||||
}
|
||||
if (password === "") {
|
||||
statusBox.innerText = "A password is required!"
|
||||
return
|
||||
}
|
||||
|
||||
showInput(2)
|
||||
showElements(true)
|
||||
statusBox.innerText = "Signing in..."
|
||||
showInput(2)
|
||||
showElements(true)
|
||||
|
||||
async function hashpass(pass) {
|
||||
let key = pass
|
||||
for (let i = 0; i < 128; i++) {
|
||||
key = await hashwasm.sha3(key)
|
||||
}
|
||||
return key
|
||||
}
|
||||
async function hashpass(pass) {
|
||||
return await hashwasm.argon2id({
|
||||
password: pass,
|
||||
salt: new TextEncoder().encode("I munch Burgers!!"),
|
||||
parallelism: 1,
|
||||
iterations: 32,
|
||||
memorySize: 19264,
|
||||
hashLength: 32,
|
||||
outputType: "hex"
|
||||
})
|
||||
}
|
||||
|
||||
fetch("/api/login", {
|
||||
async function migrateLegacyPassword(secretKey, password) {
|
||||
return await fetch("/api/changepassword", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
username: username,
|
||||
password: await hashpass(password),
|
||||
passwordchange: "no",
|
||||
newpass: "null"
|
||||
secretKey: secretKey,
|
||||
newPassword: password,
|
||||
migration: true
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
"Content-Type": "application/json; charset=UTF-8",
|
||||
}
|
||||
})
|
||||
.then((response) => response)
|
||||
.then((response) => {
|
||||
async function doStuff() {
|
||||
let responseData = await response.json()
|
||||
if (response.status === 200) {
|
||||
localStorage.setItem("DONOTSHARE-secretkey", responseData["key"])
|
||||
localStorage.setItem("DONOTSHARE-password", await hashwasm.sha512(password))
|
||||
|
||||
window.location.href = "/app" + window.location.search
|
||||
}
|
||||
else if (response.status === 401) {
|
||||
statusBox.innerText = "Wrong username or password..."
|
||||
showInput(1)
|
||||
showElements(true)
|
||||
} else {
|
||||
statusBox.innerText = "Something went wrong! (error code: " + response.status + ")"
|
||||
showInput(1)
|
||||
showElements(true)
|
||||
}
|
||||
}
|
||||
doStuff()
|
||||
});
|
||||
}
|
||||
doStuff()
|
||||
|
||||
async function hashpassold(pass) {
|
||||
let key = pass
|
||||
for (let i = 0; i < 128; i++) {
|
||||
key = await hashwasm.sha3(key)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
statusBox.innerText = "Hashing password..."
|
||||
let hashedPassword = await hashpass(password)
|
||||
|
||||
let response = await fetch("/api/login", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
username: username,
|
||||
password: hashedPassword,
|
||||
modern: true
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
let responseData = await response.json()
|
||||
if (response.status === 200) {
|
||||
statusBox.innerText = "Setting up encryption keys..."
|
||||
localStorage.setItem("DONOTSHARE-secretkey", responseData["key"])
|
||||
localStorage.setItem("DONOTSHARE-password", await hashwasm.argon2id({
|
||||
password: password,
|
||||
salt: new TextEncoder().encode("I love Burgerauth!!"),
|
||||
parallelism: 1,
|
||||
iterations: 32,
|
||||
memorySize: 19264,
|
||||
hashLength: 32,
|
||||
outputType: "hex"
|
||||
}))
|
||||
statusBox.innerText = "Welcome back!"
|
||||
await new Promise(r => setTimeout(r, 200))
|
||||
window.location.href = "/app" + window.location.search
|
||||
} else if (response.status === 401) {
|
||||
if (responseData["migrated"] !== true) {
|
||||
statusBox.innerText = "Migrating to new password algorithm..."
|
||||
let loginOld = await fetch("/api/login", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
username: username,
|
||||
password: hashpassold(password),
|
||||
modern: false
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
let loginDataOld = await loginOld.json()
|
||||
if (loginOld.status === 401) {
|
||||
statusBox.innerText = "Username or password incorrect!"
|
||||
showInput(1)
|
||||
showElements(true)
|
||||
} else if (loginOld.status === 200) {
|
||||
statusBox.innerText = "Setting up encryption keys..."
|
||||
localStorage.setItem("DONOTSHARE-secretkey", loginDataOld["key"])
|
||||
localStorage.setItem("DONOTSHARE-password", await hashwasm.argon2id({
|
||||
password: password,
|
||||
salt: new TextEncoder().encode("I love Burgerauth!!"),
|
||||
parallelism: 1,
|
||||
iterations: 32,
|
||||
memorySize: 19264,
|
||||
hashLength: 32,
|
||||
outputType: "hex"
|
||||
}))
|
||||
|
||||
statusBox.innerText = "Migrating password..."
|
||||
let status = await migrateLegacyPassword(loginDataOld["key"], hashedPass)
|
||||
if (status.status === 200) {
|
||||
statusBox.innerText = "Welcome back!"
|
||||
await new Promise(r => setTimeout(r, 200))
|
||||
window.location.href = "/app" + window.location.search
|
||||
} else {
|
||||
statusBox.innerText = (await status.json())["error"]
|
||||
showInput(1)
|
||||
showElements(true)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
statusBox.innerText = "Wrong username or password..."
|
||||
showInput(1)
|
||||
showElements(true)
|
||||
}
|
||||
} else if (response.status === 500) {
|
||||
statusBox.innerText = responseData["error"]
|
||||
showInput(1)
|
||||
showElements(true)
|
||||
} else {
|
||||
statusBox.innerText = "Something went wrong! (error code: " + responseData["error"] + ")"
|
||||
showInput(1)
|
||||
showElements(true)
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
backButton.addEventListener("click", () => {
|
||||
showInput(0)
|
||||
|
@ -151,16 +228,13 @@ backButton.addEventListener("click", () => {
|
|||
|
||||
showInput(0)
|
||||
|
||||
document.getElementById("signuprdirButton").addEventListener("click", function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const queryString = window.location.search;
|
||||
window.location.href = "/signup" + queryString;
|
||||
});
|
||||
|
||||
document.getElementById("privacyButton").addEventListener("click", function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const queryString = window.location.search;
|
||||
window.location.href = "/privacy" + queryString;
|
||||
});
|
||||
|
||||
function toSignup() {
|
||||
window.location.href = "/signup" + window.location.search;
|
||||
}
|
|
@ -1,58 +1,83 @@
|
|||
let client_id, redirect_uri, response_type, state, code, codemethod, secret_key, expires, nonce;
|
||||
let client_id, redirect_uri, response_type, state, code, codemethod, secret_key, nonce;
|
||||
|
||||
if (localStorage.getItem("DONOTSHARE-secretkey") === null) {
|
||||
window.location.replace("/login" + window.location.search)
|
||||
document.body.innerHTML = "Redirecting..."
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const statusBox = document.getElementById("statusBox");
|
||||
checkNetwork().then((result) => {
|
||||
if (result) {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const statusBox = document.getElementById("statusBox");
|
||||
|
||||
// Get URL parameters
|
||||
if (urlParams.has('client_id')) {
|
||||
client_id = urlParams.get('client_id')
|
||||
let name = document.getElementById("passthrough").innerText;
|
||||
statusBox.textContent = "Would you like to allow " + name + " to access your user information?";
|
||||
redirect_uri = urlParams.get('redirect_uri');
|
||||
response_type = urlParams.get('response_type');
|
||||
} else {
|
||||
window.location.replace("/dashboard");
|
||||
document.body.innerHTML = "Redirecting..."
|
||||
throw new Error();
|
||||
}
|
||||
if (urlParams.has('client_id')) {
|
||||
client_id = urlParams.get('client_id')
|
||||
let name = document.getElementById("passthrough").innerText;
|
||||
redirect_uri = urlParams.get('redirect_uri');
|
||||
statusBox.textContent = "Would you like to allow " + name + " to access your user information? You will be redirected to " + redirect_uri + " after you make your decision.";
|
||||
response_type = urlParams.get('response_type');
|
||||
} else {
|
||||
window.location.replace("/dashboard");
|
||||
document.body.innerHTML = "Redirecting..."
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
state = urlParams.has('state') ? urlParams.get('state') : "none";
|
||||
state = urlParams.has('state') ? urlParams.get('state') : "none";
|
||||
|
||||
if (urlParams.has('code_challenge')) {
|
||||
code = urlParams.get('code_challenge');
|
||||
codemethod = urlParams.get('code_challenge_method');
|
||||
} else {
|
||||
code = "none";
|
||||
codemethod = "none";
|
||||
}
|
||||
if (urlParams.has('code_challenge')) {
|
||||
code = urlParams.get('code_challenge');
|
||||
codemethod = urlParams.get('code_challenge_method');
|
||||
} else {
|
||||
code = "none";
|
||||
codemethod = "none";
|
||||
}
|
||||
|
||||
if (urlParams.has('nonce')) {
|
||||
nonce = urlParams.get('nonce');
|
||||
} else {
|
||||
nonce = "none";
|
||||
}
|
||||
if (urlParams.has('nonce')) {
|
||||
nonce = urlParams.get('nonce');
|
||||
} else {
|
||||
nonce = "none";
|
||||
}
|
||||
|
||||
// Get DONOTSHARE-secretkey from localStorage
|
||||
secret_key = localStorage.getItem("DONOTSHARE-secretkey");
|
||||
const now = new Date();
|
||||
const expireTime = now.getTime() + (21 * 1000); // 21 seconds from now
|
||||
expires = new Date(expireTime).toUTCString();
|
||||
secret_key = localStorage.getItem("DONOTSHARE-secretkey");
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
function deny() {
|
||||
document.cookie = "key=" + secret_key + "; expires=" + expires + "; path=/; SameSite=Strict";
|
||||
// Redirect to the redirect_uri so that an open redirect is not possible
|
||||
window.location.replace("/api/auth?client_id=" + client_id + "&redirect_uri=" + redirect_uri + "&code_challenge_method=" + codemethod + "&code_challenge=" + code + "&state=" + state + "&nonce=" + nonce + "&deny=true");
|
||||
}
|
||||
|
||||
function oauth() {
|
||||
document.cookie = "key=" + secret_key + "; expires=" + expires + "; path=/; SameSite=Strict";
|
||||
window.location.replace("/api/auth?client_id=" + client_id + "&redirect_uri=" + redirect_uri + "&code_challenge_method=" + codemethod + "&code_challenge=" + code + "&state=" + state + "&nonce=" + nonce + "&deny=false");
|
||||
}
|
||||
const now = new Date();
|
||||
const expireTime = now.getTime() + (21 * 1000);
|
||||
let expires = new Date(expireTime).toUTCString();
|
||||
if (navigator.cookieEnabled) {
|
||||
document.cookie = "DONOTSHARE-secretkey=" + secret_key + "; expires=" + expires + "; path=/";
|
||||
window.location.replace("/api/auth?client_id=" + client_id + "&redirect_uri=" + redirect_uri + "&code_challenge_method=" + codemethod + "&code_challenge=" + code + "&state=" + state + "&nonce=" + nonce + "&deny=false");
|
||||
} else {
|
||||
document.getElementById("statusBox").textContent = "Warning! Because cookies are disabled, your access token is sent directly in the URL. This is less secure than using cookies, but you chose this path!";
|
||||
setTimeout(() => {
|
||||
window.location.replace("/api/auth?client_id=" + client_id + "&redirect_uri=" + redirect_uri + "&code_challenge_method=" + codemethod + "&code_challenge=" + code + "&state=" + state + "&nonce=" + nonce + "&deny=false&access_token=" + secret_key);
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
||||
async function checkNetwork() {
|
||||
let loggedIn = await fetch("/api/secretkeyloggedin", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
secretKey: localStorage.getItem("DONOTSHARE-secretkey")
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
if (loggedIn.status === 200) {
|
||||
return true
|
||||
} else {
|
||||
localStorage.removeItem("DONOTSHARE-secretkey");
|
||||
localStorage.removeItem("DONOTSHARE-password");
|
||||
window.location.replace("/login" + window.location.search);
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
if (localStorage.getItem("DONOTSHARE-secretkey") !== null) {
|
||||
window.location.replace("/app" + window.location.search)
|
||||
document.body.innerHTML = "Redirecting..."
|
||||
throw new Error();
|
||||
}
|
||||
if (localStorage.getItem("DONOTSHARE-password") !== null) {
|
||||
if (localStorage.getItem("DONOTSHARE-secretkey") !== null || localStorage.getItem("DONOTSHARE-password") !== null) {
|
||||
window.location.replace("/app" + window.location.search)
|
||||
document.body.innerHTML = "Redirecting..."
|
||||
throw new Error();
|
||||
|
@ -13,109 +8,145 @@ let usernameBox = document.getElementById("usernameBox")
|
|||
let passwordBox = document.getElementById("passwordBox")
|
||||
let statusBox = document.getElementById("statusBox")
|
||||
let signupButton = document.getElementById("signupButton")
|
||||
let captchaBox = document.getElementById("captchaBox")
|
||||
let unique_token = document.getElementById("passthrough").innerText
|
||||
let loginButton = document.getElementById("loginButton")
|
||||
let inputContainer = document.getElementById("inputContainer")
|
||||
|
||||
function showElements(yesorno) {
|
||||
if (!yesorno) {
|
||||
usernameBox.classList.add("hidden")
|
||||
passwordBox.classList.add("hidden")
|
||||
inputContainer.classList.add("hidden")
|
||||
signupButton.classList.add("hidden")
|
||||
loginButton.classList.add("hidden")
|
||||
}
|
||||
else {
|
||||
usernameBox.classList.remove("hidden")
|
||||
passwordBox.classList.remove("hidden")
|
||||
inputContainer.classList.remove("hidden")
|
||||
signupButton.classList.remove("hidden")
|
||||
loginButton.classList.remove("hidden")
|
||||
}
|
||||
}
|
||||
|
||||
complete = new Event("completed");
|
||||
window.returnCode = undefined;
|
||||
window.returnVar = undefined;
|
||||
|
||||
// This is for the WASM code to call when it's done. Do not remove it, even if it looks like it's never called.
|
||||
|
||||
function WASMComplete() {
|
||||
window.dispatchEvent(complete);
|
||||
}
|
||||
|
||||
signupButton.addEventListener("click", () => {
|
||||
async function doStuff() {
|
||||
let username = usernameBox.value
|
||||
let password = passwordBox.value
|
||||
let captcha = captchaBox.value
|
||||
let username = usernameBox.value
|
||||
let password = passwordBox.value
|
||||
|
||||
if (username === "") {
|
||||
statusBox.innerText = "A username is required!"
|
||||
if (username === "") {
|
||||
statusBox.innerText = "A username is required!"
|
||||
return
|
||||
}
|
||||
|
||||
if ((username).length > 20) {
|
||||
statusBox.innerText = "Username cannot be more than 20 characters!"
|
||||
return
|
||||
}
|
||||
if (password === "") {
|
||||
statusBox.innerText = "A password is required!"
|
||||
return
|
||||
}
|
||||
if ((password).length < 8) {
|
||||
statusBox.innerText = "8 or more characters are required!"
|
||||
return
|
||||
}
|
||||
|
||||
async function hashpass(pass) {
|
||||
return await hashwasm.argon2id({
|
||||
password: pass,
|
||||
salt: new TextEncoder().encode("I munch Burgers!!"),
|
||||
parallelism: 1,
|
||||
iterations: 32,
|
||||
memorySize: 19264,
|
||||
hashLength: 32,
|
||||
outputType: "hex"
|
||||
})
|
||||
}
|
||||
|
||||
showElements(false)
|
||||
statusBox.innerText = "Computing PoW Challenge... (this may take up to 5 minutes at worst, 3 seconds at best)"
|
||||
|
||||
/*
|
||||
* Compiled version of:
|
||||
* hashcat-wasm (https://concord.hectabit.org/hectabit/hashcat-wasm)
|
||||
* (c) Arzumify
|
||||
* @license AGPL-3.0
|
||||
* Since this is my software, if you use it with proprietary servers, I will make sure you will walk across hot coals (just kidding, probably).
|
||||
* I'm not kidding about the license though.
|
||||
* I should stop including comments into JS and possibly minify this code. Oh, well.
|
||||
*/
|
||||
|
||||
window.resourceExtra = "I love Burgerauth!!"
|
||||
|
||||
const go = new Go();
|
||||
WebAssembly.instantiateStreaming(fetch("/static/wasm/hashcat.wasm"), go.importObject).then((result) => {
|
||||
go.run(result.instance);
|
||||
})
|
||||
|
||||
window.addEventListener("completed", async () => {
|
||||
if (window.returnCode === 1) {
|
||||
statusBox.innerText = "Please do not expose your computer to cosmic rays (an impossible logical event has occurred)."
|
||||
showElements(true)
|
||||
return
|
||||
}
|
||||
if ((username).length > 20) {
|
||||
statusBox.innerText = "Username cannot be more than 20 characters!"
|
||||
return
|
||||
}
|
||||
if (password === "") {
|
||||
statusBox.innerText = "A password is required!"
|
||||
return
|
||||
}
|
||||
if ((password).length < 8) {
|
||||
statusBox.innerText = "8 or more characters are required!"
|
||||
return
|
||||
}
|
||||
if (captcha === "") {
|
||||
statusBox.innerText = "Please complete the captcha!"
|
||||
} else if (window.returnCode === 2) {
|
||||
statusBox.innerText = "The PoW Challenge has failed. Please try again."
|
||||
showElements(true)
|
||||
return
|
||||
}
|
||||
|
||||
showElements(false)
|
||||
statusBox.innerText = "Creating account, please hold on..."
|
||||
|
||||
async function hashpass(pass) {
|
||||
let key = pass
|
||||
for (let i = 0; i < 128; i++) {
|
||||
key = await hashwasm.sha3(key)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
|
||||
statusBox.innerText = "Hashing password..."
|
||||
let hashedPass = await hashpass(password)
|
||||
statusBox.innerText = "Contacting server..."
|
||||
fetch("/api/signup", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
username: username,
|
||||
password: await hashpass(password),
|
||||
captcha: captcha,
|
||||
unique_token: unique_token
|
||||
password: hashedPass,
|
||||
stamp: window.returnVar
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
.then((response) => response)
|
||||
.then((response) => {
|
||||
async function doStuff() {
|
||||
let responseData = await response.json()
|
||||
console.log(responseData)
|
||||
.then(async (response) => {
|
||||
let responseData = await response.json()
|
||||
console.log(responseData)
|
||||
|
||||
if (response.status === 200) {
|
||||
statusBox.innerText = "Redirecting..."
|
||||
localStorage.setItem("DONOTSHARE-secretkey", responseData["key"])
|
||||
localStorage.setItem("DONOTSHARE-password", await hashwasm.sha512(password))
|
||||
if (response.status === 200) {
|
||||
statusBox.innerText = "Setting up encryption keys..."
|
||||
localStorage.setItem("DONOTSHARE-secretkey", responseData["key"])
|
||||
localStorage.setItem("DONOTSHARE-password", await hashwasm.argon2id({
|
||||
password: password,
|
||||
salt: new TextEncoder().encode("I love Burgerauth!!"),
|
||||
parallelism: 1,
|
||||
iterations: 32,
|
||||
memorySize: 19264,
|
||||
hashLength: 32,
|
||||
outputType: "hex"
|
||||
}))
|
||||
|
||||
window.location.href = "/app" + window.location.search
|
||||
} else if (response.status === 409) {
|
||||
statusBox.innerText = "Username already taken!"
|
||||
showElements(true)
|
||||
} else if (response.status === 401) {
|
||||
statusBox.innerText = "CAPTCHA has expired!"
|
||||
} else if (response.status === 403) {
|
||||
statusBox.innerText = "CAPTCHA is incorrect!"
|
||||
} else {
|
||||
statusBox.innerText = "Something went wrong!"
|
||||
showElements(true)
|
||||
}
|
||||
statusBox.innerText = "Welcome!"
|
||||
await new Promise(r => setTimeout(r, 200))
|
||||
window.location.href = "/app" + window.location.search
|
||||
} else if (response.status === 409) {
|
||||
statusBox.innerText = "Username already taken!"
|
||||
showElements(true)
|
||||
} else if (response.status === 500) {
|
||||
statusBox.innerText = responseData["error"]
|
||||
showElements(true)
|
||||
} else {
|
||||
statusBox.innerText = "Something went wrong! (error code: " + responseData["error"] + ")"
|
||||
showElements(true)
|
||||
}
|
||||
doStuff()
|
||||
});
|
||||
}
|
||||
doStuff()
|
||||
});
|
||||
|
||||
document.getElementById("loginButton").addEventListener("click", function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const queryString = window.location.search;
|
||||
window.location.href = "/login" + queryString;
|
||||
});
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
document.getElementById("privacyButton").addEventListener("click", function(event) {
|
||||
event.preventDefault();
|
||||
|
@ -123,3 +154,7 @@ document.getElementById("privacyButton").addEventListener("click", function(even
|
|||
const queryString = window.location.search;
|
||||
window.location.href = "/privacy" + queryString;
|
||||
});
|
||||
|
||||
function toLogin() {
|
||||
window.location.href = "/login" + window.location.search;
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
let clientId
|
||||
const redirectUri = window.location.href.replace(window.location.search, "")
|
||||
let authorizationEndpoint
|
||||
let tokenEndpoint
|
||||
let userinfoEndpoint
|
||||
|
||||
function generateCodeVerifier() {
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
|
||||
const length = 128;
|
||||
return Array.from(crypto.getRandomValues(new Uint8Array(length)))
|
||||
.map((x) => charset[x % charset.length])
|
||||
.join("");
|
||||
}
|
||||
|
||||
async function createCodeChallenge(codeVerifier) {
|
||||
const buffer = new TextEncoder().encode(codeVerifier);
|
||||
const hashArrayBuffer = await crypto.subtle.digest('SHA-256', buffer);
|
||||
return btoa(String.fromCharCode(...new Uint8Array(hashArrayBuffer)))
|
||||
.replace(/=/g, '')
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_');
|
||||
}
|
||||
|
||||
function authorize() {
|
||||
const codeVerifier = generateCodeVerifier();
|
||||
localStorage.setItem('codeVerifier', codeVerifier); // Store code verifier
|
||||
createCodeChallenge(codeVerifier)
|
||||
.then((codeChallenge) => {
|
||||
window.location.href = `${authorizationEndpoint}?response_type=code&client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&code_challenge=${codeChallenge}&code_challenge_method=S256`;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error generating code challenge:', error);
|
||||
});
|
||||
}
|
||||
|
||||
async function exchangeCodeForToken(code) {
|
||||
const codeVerifier = localStorage.getItem('codeVerifier'); // Retrieve code verifier
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('client_id', String(clientId));
|
||||
formData.append('code', String(code));
|
||||
formData.append('redirect_uri', String(redirectUri));
|
||||
formData.append('grant_type', 'authorization_code');
|
||||
formData.append('code_verifier', String(codeVerifier));
|
||||
|
||||
let response
|
||||
if (localStorage.getItem('noPost') !== "true") {
|
||||
response = await fetch(tokenEndpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
body: formData
|
||||
});
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const accessToken = data["access_token"];
|
||||
const idToken = data["id_token"];
|
||||
|
||||
fetch(userinfoEndpoint, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${idToken}`
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
async function doStuff() {
|
||||
if (response.status === 200) {
|
||||
const userinfoData = await response.json();
|
||||
console.log(accessToken, idToken)
|
||||
console.log("User:", userinfoData.name)
|
||||
console.log("Sub:", userinfoData.sub);
|
||||
document.getElementById("text").innerText = "Authenticated, " + userinfoData.name + ", beginning AES Key Share...";
|
||||
localStorage.setItem("user", userinfoData.name)
|
||||
localStorage.setItem("sub", userinfoData.sub)
|
||||
localStorage.setItem("keyShareUri", document.getElementById("server_uri").innerText + "/aeskeyshare");
|
||||
localStorage.setItem("referrer", redirectUri);
|
||||
localStorage.setItem("BURGERAUTH-RDIR-TOKEN", accessToken);
|
||||
window.location.replace("/keyexchangetester");
|
||||
} else {
|
||||
document.getElementById("text").innerText = "Authentication failed"
|
||||
}
|
||||
}
|
||||
doStuff()
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
clientId = document.getElementById("client_id").innerText;
|
||||
authorizationEndpoint = document.getElementById("server_uri").innerText + "/login";
|
||||
tokenEndpoint = document.getElementById("server_uri").innerText + "/api/tokenauth";
|
||||
userinfoEndpoint = document.getElementById("server_uri").innerText + "/userinfo";
|
||||
|
||||
console.log({
|
||||
clientId,
|
||||
redirectUri,
|
||||
authorizationEndpoint,
|
||||
tokenEndpoint,
|
||||
userinfoEndpoint
|
||||
});
|
||||
|
||||
if (localStorage.getItem("user") !== null) {
|
||||
document.getElementById("text").innerText = "Welcome back, " + localStorage.getItem("user")
|
||||
}
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (urlParams.get('code')) {
|
||||
await exchangeCodeForToken(urlParams.get('code'));
|
||||
} else if (urlParams.get('error')) {
|
||||
if (urlParams.get('error') === "access_denied") {
|
||||
document.getElementById("text").innerText = "Access denied"
|
||||
} else {
|
||||
document.getElementById("text").innerText = "Authentication failed (error code: " + urlParams.get('error') + ")"
|
||||
}
|
||||
} else if (localStorage.getItem("DONOTSHARE-EXCHANGED-KEY") !== null) {
|
||||
document.getElementById("text").style.overflowWrap = "break-word"
|
||||
document.getElementById("text").innerText = "AES Key Share complete! Authenticated as " + localStorage.getItem("user") + ", key is " + localStorage.getItem("DONOTSHARE-EXCHANGED-KEY") + "."
|
||||
localStorage.removeItem("referrer")
|
||||
localStorage.removeItem("keyShareUri")
|
||||
localStorage.removeItem("key")
|
||||
localStorage.removeItem("BURGERAUTH-RDIR-TOKEN")
|
||||
localStorage.removeItem("codeVerifier")
|
||||
localStorage.removeItem("sub")
|
||||
localStorage.removeItem("DONOTSHARE-EXCHANGED-KEY")
|
||||
localStorage.removeItem("user")
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', main);
|
|
@ -0,0 +1,567 @@
|
|||
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
|
||||
|
||||
/*
|
||||
* wasm_exec (https://github.com/golang/go)
|
||||
* (c) The Go Authors
|
||||
* @license BSD-3-Clause
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
(() => {
|
||||
const enosys = () => {
|
||||
const err = new Error("not implemented");
|
||||
err.code = "ENOSYS";
|
||||
return err;
|
||||
};
|
||||
|
||||
if (!globalThis.fs) {
|
||||
let outputBuf = "";
|
||||
globalThis.fs = {
|
||||
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
|
||||
writeSync(fd, buf) {
|
||||
outputBuf += decoder.decode(buf);
|
||||
const nl = outputBuf.lastIndexOf("\n");
|
||||
if (nl != -1) {
|
||||
console.log(outputBuf.substring(0, nl));
|
||||
outputBuf = outputBuf.substring(nl + 1);
|
||||
}
|
||||
return buf.length;
|
||||
},
|
||||
write(fd, buf, offset, length, position, callback) {
|
||||
if (offset !== 0 || length !== buf.length || position !== null) {
|
||||
callback(enosys());
|
||||
return;
|
||||
}
|
||||
const n = this.writeSync(fd, buf);
|
||||
callback(null, n);
|
||||
},
|
||||
chmod(path, mode, callback) { callback(enosys()); },
|
||||
chown(path, uid, gid, callback) { callback(enosys()); },
|
||||
close(fd, callback) { callback(enosys()); },
|
||||
fchmod(fd, mode, callback) { callback(enosys()); },
|
||||
fchown(fd, uid, gid, callback) { callback(enosys()); },
|
||||
fstat(fd, callback) { callback(enosys()); },
|
||||
fsync(fd, callback) { callback(null); },
|
||||
ftruncate(fd, length, callback) { callback(enosys()); },
|
||||
lchown(path, uid, gid, callback) { callback(enosys()); },
|
||||
link(path, link, callback) { callback(enosys()); },
|
||||
lstat(path, callback) { callback(enosys()); },
|
||||
mkdir(path, perm, callback) { callback(enosys()); },
|
||||
open(path, flags, mode, callback) { callback(enosys()); },
|
||||
read(fd, buffer, offset, length, position, callback) { callback(enosys()); },
|
||||
readdir(path, callback) { callback(enosys()); },
|
||||
readlink(path, callback) { callback(enosys()); },
|
||||
rename(from, to, callback) { callback(enosys()); },
|
||||
rmdir(path, callback) { callback(enosys()); },
|
||||
stat(path, callback) { callback(enosys()); },
|
||||
symlink(path, link, callback) { callback(enosys()); },
|
||||
truncate(path, length, callback) { callback(enosys()); },
|
||||
unlink(path, callback) { callback(enosys()); },
|
||||
utimes(path, atime, mtime, callback) { callback(enosys()); },
|
||||
};
|
||||
}
|
||||
|
||||
if (!globalThis.process) {
|
||||
globalThis.process = {
|
||||
getuid() { return -1; },
|
||||
getgid() { return -1; },
|
||||
geteuid() { return -1; },
|
||||
getegid() { return -1; },
|
||||
getgroups() { throw enosys(); },
|
||||
pid: -1,
|
||||
ppid: -1,
|
||||
umask() { throw enosys(); },
|
||||
cwd() { throw enosys(); },
|
||||
chdir() { throw enosys(); },
|
||||
}
|
||||
}
|
||||
|
||||
if (!globalThis.crypto) {
|
||||
throw new Error("globalThis.crypto is not available, polyfill required (crypto.getRandomValues only)");
|
||||
}
|
||||
|
||||
if (!globalThis.performance) {
|
||||
throw new Error("globalThis.performance is not available, polyfill required (performance.now only)");
|
||||
}
|
||||
|
||||
if (!globalThis.TextEncoder) {
|
||||
throw new Error("globalThis.TextEncoder is not available, polyfill required");
|
||||
}
|
||||
|
||||
if (!globalThis.TextDecoder) {
|
||||
throw new Error("globalThis.TextDecoder is not available, polyfill required");
|
||||
}
|
||||
|
||||
const encoder = new TextEncoder("utf-8");
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
|
||||
globalThis.Go = class {
|
||||
constructor() {
|
||||
this.argv = ["js"];
|
||||
this.env = {};
|
||||
this.exit = (code) => {
|
||||
if (code !== 0) {
|
||||
console.warn("exit code:", code);
|
||||
}
|
||||
};
|
||||
this._exitPromise = new Promise((resolve) => {
|
||||
this._resolveExitPromise = resolve;
|
||||
});
|
||||
this._pendingEvent = null;
|
||||
this._scheduledTimeouts = new Map();
|
||||
this._nextCallbackTimeoutID = 1;
|
||||
|
||||
const setInt64 = (addr, v) => {
|
||||
this.mem.setUint32(addr + 0, v, true);
|
||||
this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
|
||||
}
|
||||
|
||||
const setInt32 = (addr, v) => {
|
||||
this.mem.setUint32(addr + 0, v, true);
|
||||
}
|
||||
|
||||
const getInt64 = (addr) => {
|
||||
const low = this.mem.getUint32(addr + 0, true);
|
||||
const high = this.mem.getInt32(addr + 4, true);
|
||||
return low + high * 4294967296;
|
||||
}
|
||||
|
||||
const loadValue = (addr) => {
|
||||
const f = this.mem.getFloat64(addr, true);
|
||||
if (f === 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (!isNaN(f)) {
|
||||
return f;
|
||||
}
|
||||
|
||||
const id = this.mem.getUint32(addr, true);
|
||||
return this._values[id];
|
||||
}
|
||||
|
||||
const storeValue = (addr, v) => {
|
||||
const nanHead = 0x7FF80000;
|
||||
|
||||
if (typeof v === "number" && v !== 0) {
|
||||
if (isNaN(v)) {
|
||||
this.mem.setUint32(addr + 4, nanHead, true);
|
||||
this.mem.setUint32(addr, 0, true);
|
||||
return;
|
||||
}
|
||||
this.mem.setFloat64(addr, v, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (v === undefined) {
|
||||
this.mem.setFloat64(addr, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
let id = this._ids.get(v);
|
||||
if (id === undefined) {
|
||||
id = this._idPool.pop();
|
||||
if (id === undefined) {
|
||||
id = this._values.length;
|
||||
}
|
||||
this._values[id] = v;
|
||||
this._goRefCounts[id] = 0;
|
||||
this._ids.set(v, id);
|
||||
}
|
||||
this._goRefCounts[id]++;
|
||||
let typeFlag = 0;
|
||||
switch (typeof v) {
|
||||
case "object":
|
||||
if (v !== null) {
|
||||
typeFlag = 1;
|
||||
}
|
||||
break;
|
||||
case "string":
|
||||
typeFlag = 2;
|
||||
break;
|
||||
case "symbol":
|
||||
typeFlag = 3;
|
||||
break;
|
||||
case "function":
|
||||
typeFlag = 4;
|
||||
break;
|
||||
}
|
||||
this.mem.setUint32(addr + 4, nanHead | typeFlag, true);
|
||||
this.mem.setUint32(addr, id, true);
|
||||
}
|
||||
|
||||
const loadSlice = (addr) => {
|
||||
const array = getInt64(addr + 0);
|
||||
const len = getInt64(addr + 8);
|
||||
return new Uint8Array(this._inst.exports.mem.buffer, array, len);
|
||||
}
|
||||
|
||||
const loadSliceOfValues = (addr) => {
|
||||
const array = getInt64(addr + 0);
|
||||
const len = getInt64(addr + 8);
|
||||
const a = new Array(len);
|
||||
for (let i = 0; i < len; i++) {
|
||||
a[i] = loadValue(array + i * 8);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
const loadString = (addr) => {
|
||||
const saddr = getInt64(addr + 0);
|
||||
const len = getInt64(addr + 8);
|
||||
return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
|
||||
}
|
||||
|
||||
const timeOrigin = Date.now() - performance.now();
|
||||
this.importObject = {
|
||||
_gotest: {
|
||||
add: (a, b) => a + b,
|
||||
},
|
||||
gojs: {
|
||||
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
|
||||
// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
|
||||
// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
|
||||
// This changes the SP, thus we have to update the SP used by the imported function.
|
||||
|
||||
// func wasmExit(code int32)
|
||||
"runtime.wasmExit": (sp) => {
|
||||
sp >>>= 0;
|
||||
const code = this.mem.getInt32(sp + 8, true);
|
||||
this.exited = true;
|
||||
delete this._inst;
|
||||
delete this._values;
|
||||
delete this._goRefCounts;
|
||||
delete this._ids;
|
||||
delete this._idPool;
|
||||
this.exit(code);
|
||||
},
|
||||
|
||||
// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
|
||||
"runtime.wasmWrite": (sp) => {
|
||||
sp >>>= 0;
|
||||
const fd = getInt64(sp + 8);
|
||||
const p = getInt64(sp + 16);
|
||||
const n = this.mem.getInt32(sp + 24, true);
|
||||
fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n));
|
||||
},
|
||||
|
||||
// func resetMemoryDataView()
|
||||
"runtime.resetMemoryDataView": (sp) => {
|
||||
sp >>>= 0;
|
||||
this.mem = new DataView(this._inst.exports.mem.buffer);
|
||||
},
|
||||
|
||||
// func nanotime1() int64
|
||||
"runtime.nanotime1": (sp) => {
|
||||
sp >>>= 0;
|
||||
setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
|
||||
},
|
||||
|
||||
// func walltime() (sec int64, nsec int32)
|
||||
"runtime.walltime": (sp) => {
|
||||
sp >>>= 0;
|
||||
const msec = (new Date).getTime();
|
||||
setInt64(sp + 8, msec / 1000);
|
||||
this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
|
||||
},
|
||||
|
||||
// func scheduleTimeoutEvent(delay int64) int32
|
||||
"runtime.scheduleTimeoutEvent": (sp) => {
|
||||
sp >>>= 0;
|
||||
const id = this._nextCallbackTimeoutID;
|
||||
this._nextCallbackTimeoutID++;
|
||||
this._scheduledTimeouts.set(id, setTimeout(
|
||||
() => {
|
||||
this._resume();
|
||||
while (this._scheduledTimeouts.has(id)) {
|
||||
// for some reason Go failed to register the timeout event, log and try again
|
||||
// (temporary workaround for https://github.com/golang/go/issues/28975)
|
||||
console.warn("scheduleTimeoutEvent: missed timeout event");
|
||||
this._resume();
|
||||
}
|
||||
},
|
||||
getInt64(sp + 8),
|
||||
));
|
||||
this.mem.setInt32(sp + 16, id, true);
|
||||
},
|
||||
|
||||
// func clearTimeoutEvent(id int32)
|
||||
"runtime.clearTimeoutEvent": (sp) => {
|
||||
sp >>>= 0;
|
||||
const id = this.mem.getInt32(sp + 8, true);
|
||||
clearTimeout(this._scheduledTimeouts.get(id));
|
||||
this._scheduledTimeouts.delete(id);
|
||||
},
|
||||
|
||||
// func getRandomData(r []byte)
|
||||
"runtime.getRandomData": (sp) => {
|
||||
sp >>>= 0;
|
||||
crypto.getRandomValues(loadSlice(sp + 8));
|
||||
},
|
||||
|
||||
// func finalizeRef(v ref)
|
||||
"syscall/js.finalizeRef": (sp) => {
|
||||
sp >>>= 0;
|
||||
const id = this.mem.getUint32(sp + 8, true);
|
||||
this._goRefCounts[id]--;
|
||||
if (this._goRefCounts[id] === 0) {
|
||||
const v = this._values[id];
|
||||
this._values[id] = null;
|
||||
this._ids.delete(v);
|
||||
this._idPool.push(id);
|
||||
}
|
||||
},
|
||||
|
||||
// func stringVal(value string) ref
|
||||
"syscall/js.stringVal": (sp) => {
|
||||
sp >>>= 0;
|
||||
storeValue(sp + 24, loadString(sp + 8));
|
||||
},
|
||||
|
||||
// func valueGet(v ref, p string) ref
|
||||
"syscall/js.valueGet": (sp) => {
|
||||
sp >>>= 0;
|
||||
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
|
||||
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||
storeValue(sp + 32, result);
|
||||
},
|
||||
|
||||
// func valueSet(v ref, p string, x ref)
|
||||
"syscall/js.valueSet": (sp) => {
|
||||
sp >>>= 0;
|
||||
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
|
||||
},
|
||||
|
||||
// func valueDelete(v ref, p string)
|
||||
"syscall/js.valueDelete": (sp) => {
|
||||
sp >>>= 0;
|
||||
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
|
||||
},
|
||||
|
||||
// func valueIndex(v ref, i int) ref
|
||||
"syscall/js.valueIndex": (sp) => {
|
||||
sp >>>= 0;
|
||||
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
|
||||
},
|
||||
|
||||
// valueSetIndex(v ref, i int, x ref)
|
||||
"syscall/js.valueSetIndex": (sp) => {
|
||||
sp >>>= 0;
|
||||
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
|
||||
},
|
||||
|
||||
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
||||
"syscall/js.valueCall": (sp) => {
|
||||
sp >>>= 0;
|
||||
try {
|
||||
const v = loadValue(sp + 8);
|
||||
const m = Reflect.get(v, loadString(sp + 16));
|
||||
const args = loadSliceOfValues(sp + 32);
|
||||
const result = Reflect.apply(m, v, args);
|
||||
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||
storeValue(sp + 56, result);
|
||||
this.mem.setUint8(sp + 64, 1);
|
||||
} catch (err) {
|
||||
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||
storeValue(sp + 56, err);
|
||||
this.mem.setUint8(sp + 64, 0);
|
||||
}
|
||||
},
|
||||
|
||||
// func valueInvoke(v ref, args []ref) (ref, bool)
|
||||
"syscall/js.valueInvoke": (sp) => {
|
||||
sp >>>= 0;
|
||||
try {
|
||||
const v = loadValue(sp + 8);
|
||||
const args = loadSliceOfValues(sp + 16);
|
||||
const result = Reflect.apply(v, undefined, args);
|
||||
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||
storeValue(sp + 40, result);
|
||||
this.mem.setUint8(sp + 48, 1);
|
||||
} catch (err) {
|
||||
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||
storeValue(sp + 40, err);
|
||||
this.mem.setUint8(sp + 48, 0);
|
||||
}
|
||||
},
|
||||
|
||||
// func valueNew(v ref, args []ref) (ref, bool)
|
||||
"syscall/js.valueNew": (sp) => {
|
||||
sp >>>= 0;
|
||||
try {
|
||||
const v = loadValue(sp + 8);
|
||||
const args = loadSliceOfValues(sp + 16);
|
||||
const result = Reflect.construct(v, args);
|
||||
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||
storeValue(sp + 40, result);
|
||||
this.mem.setUint8(sp + 48, 1);
|
||||
} catch (err) {
|
||||
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||
storeValue(sp + 40, err);
|
||||
this.mem.setUint8(sp + 48, 0);
|
||||
}
|
||||
},
|
||||
|
||||
// func valueLength(v ref) int
|
||||
"syscall/js.valueLength": (sp) => {
|
||||
sp >>>= 0;
|
||||
setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
|
||||
},
|
||||
|
||||
// valuePrepareString(v ref) (ref, int)
|
||||
"syscall/js.valuePrepareString": (sp) => {
|
||||
sp >>>= 0;
|
||||
const str = encoder.encode(String(loadValue(sp + 8)));
|
||||
storeValue(sp + 16, str);
|
||||
setInt64(sp + 24, str.length);
|
||||
},
|
||||
|
||||
// valueLoadString(v ref, b []byte)
|
||||
"syscall/js.valueLoadString": (sp) => {
|
||||
sp >>>= 0;
|
||||
const str = loadValue(sp + 8);
|
||||
loadSlice(sp + 16).set(str);
|
||||
},
|
||||
|
||||
// func valueInstanceOf(v ref, t ref) bool
|
||||
"syscall/js.valueInstanceOf": (sp) => {
|
||||
sp >>>= 0;
|
||||
this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
|
||||
},
|
||||
|
||||
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
||||
"syscall/js.copyBytesToGo": (sp) => {
|
||||
sp >>>= 0;
|
||||
const dst = loadSlice(sp + 8);
|
||||
const src = loadValue(sp + 32);
|
||||
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
|
||||
this.mem.setUint8(sp + 48, 0);
|
||||
return;
|
||||
}
|
||||
const toCopy = src.subarray(0, dst.length);
|
||||
dst.set(toCopy);
|
||||
setInt64(sp + 40, toCopy.length);
|
||||
this.mem.setUint8(sp + 48, 1);
|
||||
},
|
||||
|
||||
// func copyBytesToJS(dst ref, src []byte) (int, bool)
|
||||
"syscall/js.copyBytesToJS": (sp) => {
|
||||
sp >>>= 0;
|
||||
const dst = loadValue(sp + 8);
|
||||
const src = loadSlice(sp + 16);
|
||||
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
|
||||
this.mem.setUint8(sp + 48, 0);
|
||||
return;
|
||||
}
|
||||
const toCopy = src.subarray(0, dst.length);
|
||||
dst.set(toCopy);
|
||||
setInt64(sp + 40, toCopy.length);
|
||||
this.mem.setUint8(sp + 48, 1);
|
||||
},
|
||||
|
||||
"debug": (value) => {
|
||||
console.log(value);
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async run(instance) {
|
||||
if (!(instance instanceof WebAssembly.Instance)) {
|
||||
throw new Error("Go.run: WebAssembly.Instance expected");
|
||||
}
|
||||
this._inst = instance;
|
||||
this.mem = new DataView(this._inst.exports.mem.buffer);
|
||||
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
||||
NaN,
|
||||
0,
|
||||
null,
|
||||
true,
|
||||
false,
|
||||
globalThis,
|
||||
this,
|
||||
];
|
||||
this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
|
||||
this._ids = new Map([ // mapping from JS values to reference ids
|
||||
[0, 1],
|
||||
[null, 2],
|
||||
[true, 3],
|
||||
[false, 4],
|
||||
[globalThis, 5],
|
||||
[this, 6],
|
||||
]);
|
||||
this._idPool = []; // unused ids that have been garbage collected
|
||||
this.exited = false; // whether the Go program has exited
|
||||
|
||||
// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
|
||||
let offset = 4096;
|
||||
|
||||
const strPtr = (str) => {
|
||||
const ptr = offset;
|
||||
const bytes = encoder.encode(str + "\0");
|
||||
new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
|
||||
offset += bytes.length;
|
||||
if (offset % 8 !== 0) {
|
||||
offset += 8 - (offset % 8);
|
||||
}
|
||||
return ptr;
|
||||
};
|
||||
|
||||
const argc = this.argv.length;
|
||||
|
||||
const argvPtrs = [];
|
||||
this.argv.forEach((arg) => {
|
||||
argvPtrs.push(strPtr(arg));
|
||||
});
|
||||
argvPtrs.push(0);
|
||||
|
||||
const keys = Object.keys(this.env).sort();
|
||||
keys.forEach((key) => {
|
||||
argvPtrs.push(strPtr(`${key}=${this.env[key]}`));
|
||||
});
|
||||
argvPtrs.push(0);
|
||||
|
||||
const argv = offset;
|
||||
argvPtrs.forEach((ptr) => {
|
||||
this.mem.setUint32(offset, ptr, true);
|
||||
this.mem.setUint32(offset + 4, 0, true);
|
||||
offset += 8;
|
||||
});
|
||||
|
||||
// The linker guarantees global data starts from at least wasmMinDataAddr.
|
||||
// Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr.
|
||||
const wasmMinDataAddr = 4096 + 8192;
|
||||
if (offset >= wasmMinDataAddr) {
|
||||
throw new Error("total length of command line and environment variables exceeds limit");
|
||||
}
|
||||
|
||||
this._inst.exports.run(argc, argv);
|
||||
if (this.exited) {
|
||||
this._resolveExitPromise();
|
||||
}
|
||||
await this._exitPromise;
|
||||
}
|
||||
|
||||
_resume() {
|
||||
if (this.exited) {
|
||||
throw new Error("Go program has already exited");
|
||||
}
|
||||
this._inst.exports.resume();
|
||||
if (this.exited) {
|
||||
this._resolveExitPromise();
|
||||
}
|
||||
}
|
||||
|
||||
_makeFuncWrapper(id) {
|
||||
const go = this;
|
||||
return function () {
|
||||
const event = { id: id, this: this, args: arguments };
|
||||
go._pendingEvent = event;
|
||||
go._resume();
|
||||
return event.result;
|
||||
};
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
// @license-end
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M450-450H200v-60h250v-250h60v250h250v60H510v250h-60v-250Z"/></svg>
|
Before Width: | Height: | Size: 163 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg>
|
Before Width: | Height: | Size: 209 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"/></svg>
|
Before Width: | Height: | Size: 300 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="m361-299 119-121 120 121 47-48-119-121 119-121-47-48-120 121-119-121-48 48 120 121-120 121 48 48ZM261-120q-24 0-42-18t-18-42v-570h-41v-60h188v-30h264v30h188v60h-41v570q0 24-18 42t-42 18H261Zm438-630H261v570h438v-570Zm-438 0v570-570Z"/></svg>
|
Before Width: | Height: | Size: 338 B |
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M140-160q-24 0-42-18t-18-42v-520q0-24 18-42t42-18h680q24 0 42 18t18 42v520q0 24-18 42t-42 18H140Zm0-60h680v-436H140v436Zm160-72-42-42 103-104-104-104 43-42 146 146-146 146Zm190 4v-60h220v60H490Z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="40px" viewBox="0 -960 960 960" width="40px" fill="#000000"><path d="M480-278.67q-15.38 0-26.69-11.31T442-316.67q0-15.38 11.31-26.69T480-354.67q15.38 0 26.69 11.31T518-316.67q0 15.38-11.31 26.69T480-278.67Zm-26.67-128.66q0-45.34 7.84-63.67 7.83-18.33 37.5-40.33 24.66-18 34.33-31.17 9.67-13.17 9.67-38.17 0-25.33-16.5-40.66-16.5-15.34-46.5-15.34T433-618.5q-16.67 18.17-22.33 37.17l-49.34-18Q376-639 405.57-663.83q29.57-24.84 74.43-24.84 49 0 82.5 27.84Q596-633 596-581.33q0 30.66-12.67 52-12.66 21.33-42 44.66-24 20-29.33 31.67-5.33 11.67-5.33 45.67h-53.34ZM266.67-40q-27 0-46.84-19.83Q200-79.67 200-106.67v-746.66q0-27 19.83-46.84Q239.67-920 266.67-920h426.66q27 0 46.84 19.83Q760-880.33 760-853.33v746.66q0 27-19.83 46.84Q720.33-40 693.33-40H266.67Zm0-100v33.33h426.66V-140H266.67Zm0-66.67h426.66v-546.66H266.67v546.66Zm0-613.33h426.66v-33.33H266.67V-820Zm0 0v-33.33V-820Zm0 680v33.33V-140Z"/></svg>
|
Before Width: | Height: | Size: 300 B After Width: | Height: | Size: 948 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M140-160q-24 0-42-18t-18-42v-520q0-24 18-42t42-18h680q24 0 42 18t18 42v520q0 24-18 42t-42 18H140Zm0-60h680v-436H140v436Zm160-72-42-42 103-104-104-104 43-42 146 146-146 146Zm190 4v-60h220v60H490Z"/></svg>
|
After Width: | Height: | Size: 300 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M480-313 287-506l43-43 120 120v-371h60v371l120-120 43 43-193 193ZM220-160q-24 0-42-18t-18-42v-143h60v143h520v-143h60v143q0 24-18 42t-42 18H220Z"/></svg>
|
Before Width: | Height: | Size: 249 B |
|
@ -1,55 +0,0 @@
|
|||
<svg width="527" height="533" viewBox="0 0 527 533" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_6_27)">
|
||||
<path d="M451 352.333C451 375.896 431.896 395 408.333 395H152.333C128.771 395 109.667 375.896 109.667 352.333V142.339C109.667 118.776 171.437 75 195 75H393.667C426.669 75 451 99.6613 451 132.333V352.333Z" fill="#226699"/>
|
||||
<path d="M429.667 395C429.667 418.563 410.563 437.667 387 437.667H173.667C150.104 437.667 131 418.563 131 395V139C131 95.064 130.776 96.3333 184.333 96.3333H387C410.563 96.3333 429.667 115.437 429.667 139V395Z" fill="url(#paint0_linear_6_27)"/>
|
||||
<path d="M408.333 405.667C408.333 423.341 394.008 437.667 376.333 437.667H141.667C123.992 437.667 109.667 423.341 109.667 405.667V149.667C109.667 131.992 123.992 117.667 141.667 117.667H376.333C394.008 117.667 408.333 131.992 408.333 149.667V405.667Z" fill="#E1E8ED"/>
|
||||
<path d="M158.115 426.776C158.115 434.264 151 440.333 142.221 440.333C133.453 440.333 126.339 434.264 126.339 426.776C126.339 419.299 133.453 413.219 142.221 413.219C151 413.219 158.115 419.288 158.115 426.776Z" fill="#662113"/>
|
||||
<path d="M140.536 419.224C135.416 419.811 132.088 423.224 129.688 427C126.413 432.173 118.947 437.667 109.667 437.667C97.8906 437.667 88.3333 430.509 88.3333 421.667C88.3333 412.824 97.8906 405.667 109.667 405.667V384.376C86.552 384.6 67.8853 401.176 67.8853 421.667C67.8853 442.296 86.7866 459 110.104 459C129.88 459 145.805 447.853 151.715 431.597C154.669 423.501 146.712 418.541 140.536 419.224Z" fill="url(#paint1_linear_6_27)"/>
|
||||
<path d="M158.115 341.443C158.115 348.931 151 355 142.221 355C133.453 355 126.339 348.931 126.339 341.443C126.339 333.965 133.453 327.885 142.221 327.885C151 327.885 158.115 333.955 158.115 341.443Z" fill="#662113"/>
|
||||
<path d="M140.536 333.891C135.416 334.477 132.088 337.891 129.688 341.667C126.413 346.84 118.947 352.333 109.667 352.333C97.8906 352.333 88.3333 345.176 88.3333 336.333C88.3333 327.491 97.8906 320.333 109.667 320.333V299.043C86.552 299.267 67.8853 315.843 67.8853 336.333C67.8853 356.963 86.7866 373.667 110.104 373.667C129.88 373.667 145.805 362.52 151.715 346.264C154.669 338.168 146.712 333.208 140.536 333.891Z" fill="url(#paint2_linear_6_27)"/>
|
||||
<path d="M158.115 256.109C158.115 263.597 151 269.667 142.221 269.667C133.453 269.667 126.339 263.597 126.339 256.109C126.339 248.632 133.453 242.552 142.221 242.552C151 242.552 158.115 248.621 158.115 256.109Z" fill="#662113"/>
|
||||
<path d="M140.536 248.557C135.416 249.144 132.088 252.557 129.688 256.333C126.413 261.507 118.947 267 109.667 267C97.8906 267 88.3333 259.843 88.3333 251C88.3333 242.157 97.8906 235 109.667 235V213.709C86.552 213.933 67.8853 230.509 67.8853 251C67.8853 271.629 86.7866 288.333 110.104 288.333C129.88 288.333 145.805 277.187 151.715 260.931C154.669 252.835 146.712 247.875 140.536 248.557Z" fill="url(#paint3_linear_6_27)"/>
|
||||
<path d="M158.115 170.776C158.115 178.264 151 184.333 142.221 184.333C133.453 184.333 126.339 178.264 126.339 170.776C126.339 163.299 133.453 157.219 142.221 157.219C151 157.219 158.115 163.288 158.115 170.776Z" fill="#662113"/>
|
||||
<path d="M140.536 163.224C135.416 163.811 132.088 167.224 129.688 171C126.413 176.173 118.947 181.667 109.667 181.667C97.8906 181.667 88.3333 174.509 88.3333 165.667C88.3333 156.824 97.8906 149.667 109.667 149.667V128.376C86.5626 128.589 67.8853 145.176 67.8853 165.667C67.8853 186.296 86.7866 203 110.104 203C129.88 203 145.805 191.853 151.715 175.597C154.669 167.501 146.712 162.541 140.536 163.224Z" fill="url(#paint4_linear_6_27)"/>
|
||||
<path d="M281 300.771C192.496 300.771 120.756 298.646 120.756 361.47C120.756 424.266 192.496 438.556 281 438.556C369.504 438.556 441.244 424.266 441.244 361.47C441.244 298.655 369.504 300.771 281 300.771Z" fill="#D99E82"/>
|
||||
<path d="M436.55 305.54C436.55 305.54 358.926 296.247 281 295.85C203.074 296.247 125.45 305.54 125.45 305.54C117.772 366.683 181.522 391.872 281 391.872C380.478 391.872 444.228 366.683 436.55 305.54Z" fill="#662113"/>
|
||||
<path d="M431.035 281.098L130.182 287.199C119.793 287.199 111.095 308.251 122.116 313.757C204.358 339.332 270.47 365.21 270.47 365.21C279.555 370.234 282.625 370.253 291.72 365.238C291.72 365.238 383.009 328.707 441.65 313.36C449.971 311.188 441.414 281.098 431.035 281.098Z" fill="#FFCC4D"/>
|
||||
<path d="M438.958 281.891C421.014 265.354 422.053 274.156 408.302 270.274C403.079 268.801 365.707 220.493 280.528 220.493H280.339C195.159 220.493 157.788 268.801 152.565 270.274C138.814 274.156 139.853 265.354 121.908 281.891C113.673 289.484 111.444 293.432 120.133 295.397C133.223 298.353 132.033 306.277 141.411 309.034C152.763 312.368 157.429 306.277 175.732 308.77C191.344 310.895 192.364 331.144 208.117 331.144C223.871 331.144 223.871 323.588 239.614 323.588C255.358 323.588 264.671 343.856 280.424 343.856C296.177 343.856 305.48 323.588 321.233 323.588C336.987 323.588 336.987 331.144 352.731 331.144C368.484 331.144 369.504 310.895 385.116 308.77C403.419 306.286 408.094 312.368 419.437 309.034C428.815 306.277 427.625 298.362 440.715 295.397C449.423 293.442 447.203 289.484 438.958 281.891Z" fill="#77B255"/>
|
||||
<path d="M432.838 264.022C432.838 292.204 364.857 305.512 281 305.512C197.143 305.512 129.162 292.204 129.162 264.022C129.162 212.994 138.285 212.994 281 212.994C423.715 212.994 432.838 213.003 432.838 264.022Z" fill="#DD2E44"/>
|
||||
<path d="M281 112.949C192.496 112.949 120.756 154.419 120.756 217.234C120.756 275.082 192.496 277.443 281 277.443C369.504 277.443 441.244 275.082 441.244 217.234C441.244 154.41 369.504 112.949 281 112.949Z" fill="#D99E82"/>
|
||||
<path d="M212.849 142.897C208.146 139.884 201.903 141.263 198.899 145.967C195.896 150.67 197.266 156.922 201.969 159.916C206.672 162.929 218.591 165.177 221.604 160.473C224.607 155.77 217.552 145.901 212.849 142.897ZM304.781 133.122C299.473 134.841 290.152 142.623 291.88 147.931C293.608 153.239 305.707 154.051 311.014 152.332C316.322 150.613 319.222 144.909 317.493 139.601C315.774 134.303 310.07 131.394 304.781 133.122ZM407.811 199.564C403.542 195.975 392.841 201.689 389.243 205.958C385.654 210.236 386.211 216.602 390.48 220.191C394.749 223.779 401.124 223.222 404.713 218.953C408.311 214.675 412.089 203.153 407.811 199.564ZM373.404 152.342C368.701 149.338 362.458 150.717 359.446 155.421C356.442 160.124 357.821 166.367 362.524 169.37C367.228 172.383 379.147 174.631 382.15 169.927C385.163 165.214 378.108 155.345 373.404 152.342ZM231.738 218.453C227.034 215.449 220.792 216.828 217.779 221.532C214.776 226.226 216.154 232.478 220.858 235.472C225.561 238.484 237.48 240.742 240.483 236.029C243.496 231.326 236.441 221.456 231.738 218.453ZM260.506 173.044C257.332 177.634 254.65 189.468 259.249 192.641C263.839 195.814 273.954 189.109 277.128 184.519C280.301 179.929 279.139 173.639 274.549 170.466C269.969 167.292 263.669 168.454 260.506 173.044ZM335.627 218.453C330.923 215.449 324.681 216.828 321.668 221.532C318.664 226.226 320.043 232.487 324.747 235.472C329.45 238.484 341.369 240.742 344.372 236.029C347.385 231.326 340.33 221.456 335.627 218.453ZM157.731 181.742C154.01 185.907 149.864 197.307 154.029 201.028C158.175 204.749 169.055 199.384 172.776 195.219C176.507 191.064 176.148 184.679 171.992 180.949C167.846 177.228 161.452 177.587 157.731 181.742Z" fill="#FFE8B6"/>
|
||||
</g>
|
||||
<path d="M408.333 416.333C408.333 439.896 389.229 459 365.667 459H163C139.437 459 120.333 439.896 120.333 416.333V181.667C120.333 158.104 139.437 139 163 139H365.667C389.229 139 408.333 158.104 408.333 181.667V416.333Z" fill="#3B88C3"/>
|
||||
<path d="M387 416.333C387 439.896 367.896 459 344.333 459H163C139.437 459 120.333 439.896 120.333 416.333V203C120.333 179.437 139.437 160.333 163 160.333H347.907C371.469 160.333 387 175.864 387 199.427V416.333Z" fill="url(#paint5_linear_6_27)"/>
|
||||
<path d="M163 139C144.995 139 144.536 118.499 152.333 109.667C161.208 99.6293 175 96.3333 199.672 96.3333H216.333V75H187.331C144.995 75 109.667 101.667 109.667 132.333V416.333C109.667 439.896 128.771 459 152.333 459H173.667V139H163Z" fill="#226699"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_6_27" x1="280.333" y1="96.3295" x2="280.333" y2="437.667" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#CCD6DD"/>
|
||||
<stop offset="1" stop-color="#CCD6DD" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_6_27" x1="110.118" y1="384.376" x2="110.118" y2="459" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#66757F"/>
|
||||
<stop offset="1" stop-color="#50585C"/>
|
||||
<stop offset="1" stop-color="#50585C"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_6_27" x1="110.118" y1="299.043" x2="110.118" y2="373.667" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#66757F"/>
|
||||
<stop offset="1" stop-color="#50585C"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_linear_6_27" x1="110.118" y1="213.709" x2="110.118" y2="288.333" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#66757F"/>
|
||||
<stop offset="1" stop-color="#50585C"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint4_linear_6_27" x1="110.118" y1="128.376" x2="110.118" y2="203" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#66757F"/>
|
||||
<stop offset="1" stop-color="#50585C"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint5_linear_6_27" x1="253.667" y1="160.333" x2="253.667" y2="459" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#55ACEE"/>
|
||||
<stop offset="1" stop-color="#55ACEE" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_6_27">
|
||||
<rect width="384" height="384" fill="white" transform="translate(67 75)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
Before Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 8.1 KiB |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M280-240q-17 0-28.5-11.5T240-280v-80h520v-360h80q17 0 28.5 11.5T880-680v600L720-240H280ZM80-280v-560q0-17 11.5-28.5T120-880h520q17 0 28.5 11.5T680-840v360q0 17-11.5 28.5T640-440H240L80-280Zm520-240v-280H160v280h440Zm-440 0v-280 280Z"/></svg>
|
Before Width: | Height: | Size: 338 B |
|
@ -0,0 +1,174 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 1000000 1000000"
|
||||
xml:space="preserve"
|
||||
width="1000000"
|
||||
height="1000000"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs124" />
|
||||
|
||||
|
||||
<g
|
||||
transform="matrix(2.0000001,0,0,2.0000001,-480.73603,-500.00106)"
|
||||
id="g124">
|
||||
<path
|
||||
style="fill:#f6d2a2"
|
||||
d="m 312.793,520.329 c 0.704,14.774 15.634,7.817 22.122,3.283 6.488,-4.534 7.817,-0.704 8.755,-9.381 0.576,-5.661 0.811,-11.352 0.704,-17.041 -9.851,-1.008 -19.74,1.513 -27.907,7.114 -4.065,2.97 -11.647,12.351 -3.752,15.634"
|
||||
id="path92" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 320.454,531.039 c -1.461,0.02 -2.906,-0.301 -4.221,-0.938 -3.063,-1.768 -4.921,-5.063 -4.847,-8.599 -1.966,-0.979 -3.293,-2.897 -3.518,-5.081 0.567,-5.266 3.427,-10.013 7.817,-12.976 8.433,-5.806 18.662,-8.411 28.845,-7.348 h 1.173 v 1.173 c 0.163,4.46 0.033,8.925 -0.391,13.367 v 3.909 c -0.391,6.097 -1.563,7.035 -4.69,7.817 -1.668,0.516 -3.249,1.281 -4.69,2.267 -4.498,3.473 -9.841,5.686 -15.478,6.409 z m 19.855,-32.285 c -8.21,-0.127 -16.251,2.335 -22.982,7.035 -3.535,2.441 -5.91,6.229 -6.566,10.475 0.196,1.491 1.229,2.737 2.658,3.205 h 0.782 v 0.86 c -0.23,2.761 1.019,5.438 3.283,7.035 5.994,0.93 12.092,-0.845 16.65,-4.847 1.631,-1.144 3.422,-2.039 5.316,-2.658 2.032,-0.703 2.501,-0.86 2.814,-5.706 v -3.909 c 0.366,-3.897 0.522,-7.812 0.469,-11.726 h -2.423 v 0.236 z"
|
||||
id="path93" />
|
||||
<path
|
||||
style="fill:#c7b199"
|
||||
d="m 312.793,520.329 c 2.234,-0.495 4.274,-1.637 5.863,-3.283"
|
||||
id="path94" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 312.793,521.736 c -0.756,0.237 -1.56,-0.182 -1.798,-0.938 -0.237,-0.755 0.183,-1.56 0.938,-1.798 h 0.938 c 1.652,-0.383 3.15,-1.255 4.299,-2.501 0.475,-0.626 1.367,-0.749 1.993,-0.274 0.626,0.475 0.749,1.367 0.274,1.993 v 0 c -1.478,1.698 -3.443,2.899 -5.628,3.44 h -1.016 z"
|
||||
id="path95" />
|
||||
<path
|
||||
style="fill:#74cddd"
|
||||
d="m 346.875,344.522 c -56.518,-15.634 -14.462,-87.786 31.268,-58.237 z"
|
||||
id="path96" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 347.579,346.164 h -1.094 c -16.103,-4.534 -26.031,-14.071 -27.907,-26.813 -1.356,-14.13 5.394,-27.812 17.432,-35.333 13.121,-8.301 29.982,-7.743 42.525,1.407 l 1.094,0.704 z m 7.817,-65.507 c -6.415,0.008 -12.689,1.882 -18.058,5.394 -11.143,6.915 -17.411,19.541 -16.181,32.597 1.72,11.335 10.475,19.934 24.78,24.233 l 29.705,-56.049 c -6.009,-3.758 -12.926,-5.812 -20.012,-5.941 z"
|
||||
id="path97" />
|
||||
<path
|
||||
style="fill:#74cddd"
|
||||
d="m 597.961,280.891 c 44.714,-31.268 85.128,39.086 33.145,57.299 z"
|
||||
id="path98" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 630.48,339.91 -34.395,-59.41 1.016,-0.704 c 11.708,-9.385 27.933,-10.745 41.04,-3.44 12.329,7.221 19.552,20.759 18.683,35.021 -0.782,7.817 -5.003,21.184 -25.249,28.142 z m -30.643,-58.628 31.894,55.189 c 11.834,-3.209 20.605,-13.18 22.279,-25.327 0.835,-13.209 -5.849,-25.761 -17.276,-32.441 -11.685,-6.699 -26.258,-5.681 -36.897,2.579 z"
|
||||
id="path99" />
|
||||
<path
|
||||
style="fill:#f6d2a2"
|
||||
d="m 607.576,701.999 c 11.335,7.035 32.128,28.298 15.087,38.617 -16.338,15.009 -25.562,-16.494 -39.945,-20.794 5.58,-9.016 14.528,-15.432 24.858,-17.823 z"
|
||||
id="path100" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 613.986,746.009 h -0.625 c -6.488,-0.391 -11.804,-6.723 -16.963,-12.742 -3.565,-5.187 -8.413,-9.361 -14.071,-12.117 l -1.876,-0.547 1.173,-1.954 c 5.815,-9.275 15.059,-15.878 25.718,-18.37 h 1.016 c 7.27,4.534 22.279,17.667 22.201,29.549 -0.092,4.782 -2.791,9.131 -7.035,11.335 -2.423,2.801 -5.847,4.541 -9.538,4.846 z m -29.08,-26.891 c 5.303,3.119 9.906,7.297 13.524,12.273 3.418,5.614 8.747,9.806 15.009,11.804 2.993,-0.128 5.809,-1.451 7.817,-3.674 3.476,-1.699 5.709,-5.2 5.785,-9.068 0,-9.537 -12.038,-21.497 -20.403,-26.891 -8.911,2.291 -16.638,7.842 -21.653,15.556 z"
|
||||
id="path101" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 622.663,742.101 c -0.531,-0.004 -1.015,-0.306 -1.251,-0.782 -0.827,-1.73 -1.557,-3.505 -2.189,-5.316 -0.951,-3.538 -2.718,-6.805 -5.159,-9.537 -0.561,-0.54 -0.579,-1.432 -0.039,-1.993 0.54,-0.561 1.432,-0.579 1.993,-0.039 2.699,2.947 4.679,6.479 5.785,10.319 0.613,1.705 1.317,3.375 2.111,5.003 0.34,0.691 0.062,1.527 -0.625,1.876 z"
|
||||
id="path102" />
|
||||
<path
|
||||
style="fill:#f6d2a2"
|
||||
d="m 404.566,725.997 c -13.367,2.032 -20.872,14.071 -31.972,20.168 -3.934,3.631 -10.066,3.386 -13.697,-0.547 -0.839,-0.909 -1.497,-1.97 -1.937,-3.127 -1.572,0.037 -3.073,-0.655 -4.065,-1.876 -9.693,-15.634 10.084,-26.5 20.481,-34.161 14.617,-2.814 23.607,9.615 31.19,19.543 z"
|
||||
id="path103" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 365.558,749.918 c -0.83,0.11 -1.671,0.11 -2.501,0 -2.964,-0.959 -5.416,-3.073 -6.801,-5.863 -1.532,-0.011 -2.962,-0.77 -3.83,-2.032 -9.381,-14.774 6.566,-25.953 17.119,-33.379 l 3.674,-2.658 c 14.774,-2.971 24.155,9.224 31.659,19.074 l 2.111,2.814 h -2.345 c -7.543,1.802 -14.409,5.737 -19.777,11.335 -3.6,3.31 -7.529,6.243 -11.726,8.755 -2.321,1.283 -4.93,1.956 -7.583,1.954 z m -9.38,-9.068 c 0.541,-0.119 1.101,-0.119 1.642,0 h 0.391 l 0.625,1.251 c 1.027,2.234 2.917,3.955 5.237,4.768 2.75,0.413 5.554,-0.259 7.817,-1.876 4.054,-2.423 7.852,-5.252 11.335,-8.442 5.276,-5.274 11.735,-9.214 18.839,-11.491 -7.192,-9.38 -15.634,-19.543 -27.907,-17.198 l -3.518,2.501 c -10.788,7.817 -24.155,17.041 -16.416,29.471 0.351,0.596 0.956,0.999 1.642,1.094 z"
|
||||
id="path104" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 357.194,743.977 c -0.776,0.045 -1.441,-0.548 -1.486,-1.323 -0.011,-0.188 0.016,-0.376 0.079,-0.553 0.576,-3.755 2.141,-7.289 4.534,-10.24 1.132,-1.552 2.126,-3.2 2.97,-4.925 0.324,-0.712 1.164,-1.027 1.876,-0.704 0.712,0.323 1.027,1.164 0.704,1.876 -0.908,1.889 -1.98,3.694 -3.205,5.394 -2.064,2.656 -3.386,5.812 -3.83,9.146 -0.032,0.776 -0.688,1.38 -1.464,1.348 -0.06,-0.003 -0.119,-0.009 -0.178,-0.019 z m -7.974,-419.31 c -7.817,-3.909 -12.898,-9.302 -8.364,-17.901 4.534,-8.599 12.038,-7.114 19.543,-3.205 z m 270.082,-7.505 c 7.817,-3.909 12.898,-9.302 8.364,-17.901 -4.534,-8.599 -12.038,-7.114 -19.543,-3.205 z"
|
||||
id="path105" />
|
||||
<path
|
||||
style="fill:#f6d2a2"
|
||||
d="m 670.66,518.453 c -0.704,14.774 -15.634,7.817 -22.122,3.283 -6.488,-4.534 -7.817,-0.704 -8.755,-9.381 -0.576,-5.661 -0.811,-11.352 -0.703,-17.041 9.851,-1.008 19.74,1.513 27.907,7.114 4.065,2.971 11.648,12.351 3.752,15.634"
|
||||
id="path106" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 662.999,528.85 c -5.373,-0.584 -10.509,-2.521 -14.931,-5.628 -1.441,-0.986 -3.022,-1.75 -4.69,-2.267 -3.127,-1.094 -4.299,-2.032 -4.69,-7.817 v -3.909 c -0.424,-4.442 -0.554,-8.908 -0.391,-13.367 v -1.876 h 1.173 c 10.183,-1.063 20.412,1.542 28.845,7.348 4.39,2.963 7.25,7.711 7.817,12.976 -0.225,2.184 -1.552,4.102 -3.518,5.081 0.074,3.536 -1.783,6.831 -4.847,8.599 -1.487,0.696 -3.131,0.992 -4.768,0.86 z m -22.748,-32.207 c -0.053,3.914 0.104,7.828 0.469,11.726 v 3.909 c 0,4.768 0.704,4.925 2.814,5.706 1.893,0.619 3.685,1.514 5.316,2.658 4.553,4.011 10.656,5.788 16.65,4.847 2.264,-1.598 3.513,-4.274 3.283,-7.035 v -0.938 h 0.782 c 1.429,-0.468 2.462,-1.714 2.658,-3.205 -0.657,-4.245 -3.031,-8.034 -6.566,-10.475 -7.406,-5.214 -16.366,-7.751 -25.406,-7.193 z"
|
||||
id="path107" />
|
||||
<path
|
||||
style="fill:#c7b199"
|
||||
d="m 670.66,518.453 c -2.208,-0.429 -4.244,-1.488 -5.863,-3.049"
|
||||
id="path108" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 670.66,519.86 h -1.485 c -2.189,-0.696 -4.103,-2.064 -5.472,-3.909 -0.475,-0.626 -0.352,-1.518 0.274,-1.993 0.626,-0.475 1.518,-0.352 1.993,0.274 1.149,1.247 2.648,2.118 4.299,2.501 h 0.938 c 0.863,0.151 1.441,0.974 1.29,1.837 -0.151,0.864 -0.974,1.441 -1.837,1.29 z"
|
||||
id="path109" />
|
||||
<path
|
||||
style="fill:#74cddd"
|
||||
d="m 486.098,251.03 c 56.596,0 109.44,7.817 137.268,62.537 24.78,60.895 15.634,126.637 19.777,190.972 3.283,55.267 10.475,119.133 -15.165,170.413 -26.813,53.782 -94.509,67.149 -150.01,65.351 -43.619,-1.563 -96.307,-15.634 -120.931,-55.658 -28.923,-46.903 -15.243,-116.319 -13.133,-168.302 2.501,-61.599 -16.729,-123.432 3.518,-183.78 21.028,-62.537 77.624,-76.686 138.597,-81.532"
|
||||
id="path110" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 487.583,742.101 h -9.693 c -23.301,-0.655 -46.323,-5.254 -68.087,-13.602 -22.158,-8.032 -41.113,-23.036 -54.016,-42.76 -23.451,-37.835 -19.23,-90.053 -15.634,-136.174 0.938,-11.569 1.798,-22.591 2.189,-32.91 0.414,-21.873 -0.526,-43.751 -2.814,-65.507 -3.283,-39.086 -6.723,-79.5 6.41,-118.664 8.567,-27.82 28.42,-50.764 54.72,-63.24 21.106,-10.319 46.903,-16.26 84.816,-19.23 55.814,-0.391 110.847,7.426 139.145,62.85 18.136,44.558 18.37,92.398 18.683,138.676 0,17.354 0,35.255 1.251,52.766 0,5.316 0.625,10.709 1.016,16.103 3.283,50.733 7.035,108.345 -16.338,154.935 -29.238,58.314 -102.718,66.757 -141.648,66.757 z m -1.485,-489.664 c -58.863,5.003 -116.24,17.667 -137.347,80.594 -12.976,38.617 -9.537,78.718 -6.332,117.257 2.296,21.861 3.236,43.843 2.814,65.82 -0.391,10.397 -1.329,21.419 -2.189,33.066 -3.596,45.652 -7.817,97.479 15.087,134.454 9.615,15.634 40.571,52.14 119.836,54.72 34.317,1.251 117.257,-2.658 148.525,-64.726 22.982,-45.965 19.308,-103.108 16.025,-153.528 0,-5.472 -0.704,-10.866 -1.016,-16.103 -0.86,-17.041 -1.251,-35.021 -1.251,-52.375 0,-45.965 -0.469,-93.805 -18.448,-137.581 -11.565,-23.797 -32.039,-42.079 -56.987,-50.889 -25.435,-8.035 -52.059,-11.657 -78.717,-10.709 z"
|
||||
id="path111" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
d="m 496.026,326.934 c 10.162,59.019 106.625,43.463 92.789,-16.103 -12.429,-53.391 -96.151,-38.617 -92.789,16.103"
|
||||
id="path112" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 541.912,365.472 c -6.009,0.025 -11.98,-0.952 -17.667,-2.892 -15.784,-5.222 -27.237,-18.948 -29.549,-35.411 -1.062,-12.778 3.373,-25.403 12.195,-34.708 8.366,-8.583 19.383,-14.091 31.268,-15.634 10.893,-1.724 22.051,0.2 31.737,5.472 10.451,6.104 17.812,16.364 20.246,28.22 4.292,15.119 -0.375,31.364 -12.038,41.9 -10.085,8.588 -22.945,13.226 -36.192,13.053 z m -44.479,-38.694 c 2.183,15.449 12.937,28.324 27.751,33.223 17.592,5.883 36.978,2.213 51.202,-9.693 10.742,-9.913 15.054,-24.992 11.178,-39.086 -4.99,-22.11 -26.712,-36.199 -48.935,-31.737 -24.239,2.074 -42.465,22.998 -41.196,47.293 z"
|
||||
id="path113" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
d="m 380.723,336.549 c 13.133,51.358 95.369,38.147 92.32,-13.367 -3.674,-61.756 -104.905,-50.108 -92.32,13.367"
|
||||
id="path114" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 424.656,370.397 c -8.362,0.063 -16.608,-1.952 -23.999,-5.863 -10.701,-5.799 -18.411,-15.899 -21.184,-27.751 -4.163,-16.329 1.579,-33.587 14.696,-44.167 15.808,-12.062 36.86,-14.746 55.189,-7.035 14.958,6.54 24.731,21.199 25.015,37.522 1.642,27.36 -20.09,43.307 -40.883,46.903 -2.931,0.358 -5.884,0.489 -8.834,0.391 z m -42.369,-34.161 c 5.629,22.608 28.348,36.525 51.046,31.268 19.699,-3.127 40.258,-18.136 38.695,-43.854 -0.193,-15.363 -9.369,-29.189 -23.451,-35.333 -17.426,-7.314 -37.434,-4.75 -52.453,6.723 -12.199,9.896 -17.589,25.944 -13.837,41.196 z"
|
||||
id="path115" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
d="m 507.361,398.148 c 0.752,8.139 0.752,16.329 0,24.468 -2.289,2.897 -5.528,4.891 -9.146,5.628 -4.521,-0.694 -8.379,-3.639 -10.24,-7.817 -0.502,-9.228 -0.267,-18.482 0.704,-27.673 z"
|
||||
id="path116" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 499.074,429.416 h -0.391 c -5.052,-0.785 -9.339,-4.126 -11.335,-8.833 -0.649,-6.315 -0.649,-12.68 0,-18.996 0,-2.892 0.469,-5.941 0.547,-8.911 v -2.345 l 21.106,6.488 v 1.329 c 0,2.501 0,5.159 0.391,7.817 0.706,5.58 0.706,11.227 0,16.807 v 0.391 c -1.655,2.703 -4.334,4.62 -7.426,5.316 l -2.423,0.938 h -0.469 z m -9.067,-9.849 c 1.588,3.625 4.866,6.229 8.755,6.957 l 2.189,-0.86 c 2.356,-0.567 4.401,-2.024 5.706,-4.065 0.62,-5.193 0.62,-10.441 0,-15.634 0,-2.423 0,-4.768 -0.391,-7.114 l -15.634,-4.768 c 0,2.423 0,4.847 -0.469,7.192 -0.693,6.048 -0.771,12.15 -0.235,18.214 z"
|
||||
id="path117" />
|
||||
<ellipse
|
||||
style="fill:#010101"
|
||||
cx="403.39301"
|
||||
cy="328.10599"
|
||||
rx="13.914"
|
||||
ry="15.087"
|
||||
id="ellipse117" />
|
||||
<ellipse
|
||||
style="fill:#ffffff"
|
||||
cx="409.72501"
|
||||
cy="331.54599"
|
||||
rx="3.283"
|
||||
ry="3.8299999"
|
||||
id="ellipse118" />
|
||||
<ellipse
|
||||
style="fill:#010101"
|
||||
cx="519.86798"
|
||||
cy="324.354"
|
||||
rx="13.68"
|
||||
ry="15.087"
|
||||
id="ellipse119" />
|
||||
<ellipse
|
||||
style="fill:#ffffff"
|
||||
cx="526.04401"
|
||||
cy="327.79401"
|
||||
rx="3.2049999"
|
||||
ry="3.8299999"
|
||||
id="ellipse120" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
d="m 468.275,396.975 c -6.097,14.696 3.361,44.088 19.855,22.435 -0.502,-9.228 -0.267,-18.482 0.704,-27.673 z"
|
||||
id="path120" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 476.796,428.556 c -1.43,0.014 -2.836,-0.365 -4.065,-1.094 -6.645,-3.83 -10.788,-19.543 -6.097,-31.268 v -0.625 l 23.451,-5.941 v 1.876 c 0,3.049 0,6.097 -0.547,8.99 -0.637,6.133 -0.637,12.315 0,18.448 v 1.016 c -2.571,4.791 -7.337,8.007 -12.742,8.598 z m -7.739,-30.408 c -3.361,9.146 -0.704,23.451 5.159,26.813 4.221,2.423 8.911,-1.798 12.195,-6.019 -0.595,-6.135 -0.595,-12.313 0,-18.448 0,-2.267 0,-4.69 0.469,-7.035 z"
|
||||
id="path121" />
|
||||
<path
|
||||
style="fill:#f6d2a2"
|
||||
d="m 470.073,368.677 c -9.842,0.937 -17.061,9.674 -16.125,19.517 0.181,1.897 0.663,3.753 1.429,5.498 7.817,14.071 25.171,-1.251 35.959,0 12.429,0 22.67,13.133 32.676,2.345 11.1,-12.038 -4.768,-23.451 -17.198,-29.001 z"
|
||||
id="path122" />
|
||||
<path
|
||||
style="fill:#231f20"
|
||||
d="m 515.178,401.978 c -3.974,-0.331 -7.848,-1.419 -11.413,-3.205 -3.866,-1.909 -8.055,-3.075 -12.351,-3.44 -4.477,-0.002 -8.902,0.958 -12.976,2.814 -8.755,3.049 -18.683,6.488 -24.311,-3.596 -2.839,-5.104 -2.839,-11.312 0,-16.416 3.084,-5.967 8.956,-9.99 15.634,-10.709 l 37.6,-1.642 c 9.224,3.909 19.777,11.022 21.575,19.308 1.099,8.172 -4.635,15.689 -12.807,16.788 -0.316,0.044 -0.633,0.076 -0.951,0.098 z m -23.452,-9.459 c 4.622,0.375 9.131,1.622 13.289,3.674 7.035,2.97 12.586,5.237 18.214,-0.86 2.612,-2.4 3.82,-5.966 3.205,-9.459 -1.563,-7.192 -11.491,-13.758 -19.621,-17.198 l -36.35,1.485 c -5.68,0.696 -10.651,4.147 -13.289,9.224 -2.351,4.257 -2.351,9.423 0,13.68 4.456,7.817 12.429,5.237 20.95,2.345 4.279,-1.913 8.915,-2.899 13.602,-2.891 z"
|
||||
id="path123" />
|
||||
<path
|
||||
style="fill:#010101"
|
||||
d="m 468.275,368.13 c -0.86,-19.543 36.506,-22.044 40.883,-5.628 4.378,16.416 -39.085,20.168 -40.883,5.628 z"
|
||||
id="path124" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 14 KiB |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>
|
Before Width: | Height: | Size: 516 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M290-620v-60h550v60H290Zm0 170v-60h550v60H290Zm0 170v-60h550v60H290ZM150-620q-12 0-21-9t-9-21.5q0-12.5 9-21t21.5-8.5q12.5 0 21 8.625T180-650q0 12-8.625 21T150-620Zm0 170q-12 0-21-9t-9-21.5q0-12.5 9-21t21.5-8.5q12.5 0 21 8.625T180-480q0 12-8.625 21T150-450Zm0 170q-12 0-21-9t-9-21.5q0-12.5 9-21t21.5-8.5q12.5 0 21 8.625T180-310q0 12-8.625 21T150-280Z"/></svg>
|
Before Width: | Height: | Size: 455 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M180-120q-24 0-42-18t-18-42v-600q0-24 18-42t42-18h299v60H180v600h299v60H180Zm486-185-43-43 102-102H360v-60h363L621-612l43-43 176 176-174 174Z"/></svg>
|
Before Width: | Height: | Size: 247 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M634-320q-14 0-24-10t-10-24v-132q0-14 10-24t24-10h6v-40q0-33 23.5-56.5T720-640q33 0 56.5 23.5T800-560v40h6q14 0 24 10t10 24v132q0 14-10 24t-24 10H634Zm46-200h80v-40q0-17-11.5-28.5T720-600q-17 0-28.5 11.5T680-560v40ZM280-40q-33 0-56.5-23.5T200-120v-720q0-33 23.5-56.5T280-920h400q33 0 56.5 23.5T760-840v160h-80v-40H280v480h400v-40h80v160q0 33-23.5 56.5T680-40H280Zm0-120v40h400v-40H280Zm0-640h400v-40H280v40Zm0 0v-40 40Zm0 640v40-40Z"/></svg>
|
Before Width: | Height: | Size: 538 B |
|
@ -1,61 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" href="/static/css/style.css" media="">
|
||||
<script src="/static/js/dashboard.js"></script>
|
||||
<title>User settings - {{ .identifier }}</title>
|
||||
</head>
|
||||
<body style="background-color: transparent;">
|
||||
<script>
|
||||
async function deleteacct() {
|
||||
if (confirm("Are you SURE you would like to delete your account forever?") == true) {
|
||||
await fetch(remote + "/api/deleteaccount", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
"secretKey": localStorage.getItem("DONOTSHARE-secretkey")
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
.then((response) => response)
|
||||
.then((response) => {
|
||||
async function doStuff() {
|
||||
if (response.status === 200) {
|
||||
parent.window.location.href = '/logout';
|
||||
}
|
||||
}
|
||||
doStuff()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fetch("/api/userinfo", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
"secretKey": localStorage.getItem("DONOTSHARE-secretkey")
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
async function doStuff() {
|
||||
const data = await response.json()
|
||||
if (response.status === 200) {
|
||||
document.getElementById("namebox").innerText = "Username: " + data.username;
|
||||
document.getElementById("datebox").innerText = "Account created: " + new Date(data.created * 1000).toLocaleString();
|
||||
}
|
||||
}
|
||||
doStuff()
|
||||
});
|
||||
</script>
|
||||
<div class="newoauth" style="margin: 0;">
|
||||
<h2>Account settings</h2>
|
||||
<p id="namebox">Loading...</p>
|
||||
<p id="datebox"></p>
|
||||
<button onclick="parent.window.location.href = '/logout';">Logout</button><br style="">
|
||||
<button onclick="deleteacct()" style="margin-top: 5px;">Delete Account</button>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1 +1,20 @@
|
|||
To be implemented
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Key Exchange - {{ .identifier }}</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="icon" href="/static/svg/favicon.svg">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css"/>
|
||||
<script src="/static/js/aeskeyshare.js"></script>
|
||||
<script src="/static/js/hash-wasm.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<img src="/static/img/background.png" class="background" alt="">
|
||||
<div class="inoutdiv">
|
||||
<h2>Relaying back information, please wait...</h2>
|
||||
<p id="errors">Processing information sent...</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,25 +1,51 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" href="/static/css/style.css" media="">
|
||||
<script src="/static/js/dashboard.js"></script>
|
||||
<title>Dashboard - {{ .identifier }}</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="icon" href="/static/svg/favicon.svg">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<img src="/static/img/background.png" class="background" alt="">
|
||||
<div style="position: fixed;top: 5px;"><button onclick="document.getElementById('iframe').classList.toggle('hidden');" class="acctbutton">Account</button><iframe id="iframe" src="/account" class="iframe hidden"></iframe></div>
|
||||
<div class="newoauth">
|
||||
<h2>Submit a new OAuth2 App</h2>
|
||||
<p id="status"></p>
|
||||
<p>App Name:</p>
|
||||
<input id="appidbox">
|
||||
<p>Redirect URI:</p>
|
||||
<input id="rdiruribox">
|
||||
<br>
|
||||
<button style="margin-top: 10px;" onclick="attempt()">Submit</button>
|
||||
<h2>Dashboard</h2>
|
||||
<p>Welcome to the Burgerauth dashboard!</p>
|
||||
<button id="devAcctSwitcher">Switch to developer view</button>
|
||||
</div>
|
||||
<div class="oauthlist" id="oauthlist" style="margin-bottom: 30px;">
|
||||
<h2>Your existing apps</h2>
|
||||
<div id="developers" class="hidden">
|
||||
<div class="newoauth">
|
||||
<h2>Submit a new OAuth2 App</h2>
|
||||
<p id="status"></p>
|
||||
<p>App Name:</p>
|
||||
<input id="appidbox">
|
||||
<p>Redirect URI:</p>
|
||||
<input id="rdiruribox">
|
||||
<p>Enable OpenID:</p>
|
||||
<input type="checkbox" id="openidbox">
|
||||
<p>AESKeyShare URI (optional, will add the aeskeyshare scope):</p>
|
||||
<input id="aeskeysharebox">
|
||||
<br>
|
||||
<button style="margin-top: 10px;" onclick="attempt()">Submit</button>
|
||||
</div>
|
||||
<div class="oauthlist" id="oauthlist" style="margin-bottom: 30px;">
|
||||
<h2>Your existing apps</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div id="account">
|
||||
<div class="newoauth">
|
||||
<h2>Account settings</h2>
|
||||
<p id="namebox">Loading...</p>
|
||||
<p id="datebox"></p>
|
||||
<button onclick="window.location.href = '/logout';">Logout</button><br style="">
|
||||
<button onclick="deleteacct()" style="margin-top: 5px;">Delete Account</button>
|
||||
</div>
|
||||
<div class="oauthlist" id="sessionsList" style="margin-bottom: 30px;">
|
||||
<h2>Sessions</h2>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/js/dashboard.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ .identifier }}</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="icon" href="/static/svg/favicon.svg">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<img src="/static/img/background.png" class="background" alt="">
|
||||
<div class="inoutdiv">
|
||||
<h2 class="w300">Welcome to {{ .identifier }}!</h2>
|
||||
<p>{{ .identifier }} is an instance of Burgerauth, an open-source OAuth2 client.</p>
|
||||
<p>This is running Burgerauth version 1.0.0</p>
|
||||
<button onclick="window.location.href = '/dashboard'">Open Burgerauth</button>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" id="top">
|
||||
<head>
|
||||
<title>Exchange Key - {{ .identifier }}</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="icon" href="/static/svg/favicon.svg">
|
||||
<script src="/static/js/keyexchangeclient.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<img src="/static/img/background.png" class="background" alt="">
|
||||
<div class="inoutdiv">
|
||||
<h2>Communicating with Burgerauth, please wait...</h2>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" id="top">
|
||||
<head>
|
||||
<title>Exchange Key - {{ .identifier }}</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="icon" href="/static/svg/favicon.svg">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css"/>
|
||||
<script src="/static/js/keyexchangetester.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<img src="/static/img/background.png" class="background" alt="">
|
||||
<div class="inoutdiv">
|
||||
<h2>Communicating with Burgerauth, please wait...</h2>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -3,12 +3,12 @@
|
|||
|
||||
<head>
|
||||
<title>Login - {{ .identifier }}</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
<script src="/static/js/hash-wasm.js"></script>
|
||||
<link rel="icon" href="/static/svg/favicon.svg">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css"/>
|
||||
<script src="/static/js/hash-wasm.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -16,14 +16,16 @@
|
|||
<div class="inoutdiv">
|
||||
<h2 class="w300">Login</h2>
|
||||
<p id="statusBox"></p>
|
||||
<span id="inputNameBox" style="margin-right: 10px;color: var(--text-color);"></span>
|
||||
<input id="usernameBox" class="hidden" type="text" placeholder="Enter your username">
|
||||
<input id="passwordBox" class="hidden" type="password" placeholder="Enter your password">
|
||||
<button id="signupButton">Next</button>
|
||||
<div class="inputContainer" id="inputContainer">
|
||||
<div class="vAlign"><span id="inputNameBox"></span></div>
|
||||
<input id="usernameBox" class="hidden" type="text" placeholder="Enter your username">
|
||||
<input id="passwordBox" class="hidden" type="password" placeholder="Enter your password">
|
||||
</div>
|
||||
<button id="nextButton">Next</button>
|
||||
<button id="backButton" class="hidden unimportant">Back</button>
|
||||
<button id="signupButton" class="unimportant" onclick="toSignup()">Signup</button>
|
||||
<br>
|
||||
<br>
|
||||
<p>Don't have an account? If so, <a href="/signup" id="signuprdirButton">Create one here!</a></p>
|
||||
<a href="{{ .privacy }}" id="privacyButton">Privacy & Terms</a>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
|
||||
<head>
|
||||
<title>Log out - {{ .identifier }}</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="icon" href="/static/svg/favicon.svg">
|
||||
</head>
|
||||
<p>Logging out...</p>
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<title>Authorize application - {{ .identifier }}</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" media="">
|
||||
<script src="/static/js/hash-wasm.js"></script>
|
||||
<link rel="icon" href="/static/svg/favicon.svg">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css"/>
|
||||
<script src="/static/js/hash-wasm.js"></script>
|
||||
<script src="/static/js/main.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p id="passthrough" style="display: none;">{{ .name }}</p>
|
||||
<img src="/static/img/background.png" class="background" alt="">
|
||||
<div style="position: fixed;top: 5px;"><button onclick="document.getElementById('iframe').classList.toggle('hidden');" class="acctbutton">Account</button><iframe id="iframe" src="/account" class="iframe hidden"></iframe></div>
|
||||
<div class="inoutdiv">
|
||||
<h2 class="w300">Authorise Application</h2>
|
||||
<p id="statusBox">Loading...</p>
|
||||
|
@ -22,6 +21,8 @@
|
|||
<button onclick="oauth();" style="width: 100%;margin: 0 3px 0 0;">Allow</button>
|
||||
<button onclick="deny();" style="width: 100%;margin: 0 0 0 3px;">Deny</button>
|
||||
</div>
|
||||
<br>
|
||||
<a href="/dashboard">Return to Dashboard</a>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="icon" href="/static/svg/favicon.svg">
|
||||
<meta http-equiv="refresh" content="0">
|
||||
<title>Please wait...</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Please wait...</p>
|
||||
</body>
|
||||
</html>
|
|
@ -3,12 +3,13 @@
|
|||
|
||||
<head>
|
||||
<title>Signup - {{ .identifier }}</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
<script src="/static/js/hash-wasm.js"></script>
|
||||
<link rel="icon" href="/static/svg/favicon.svg">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css"/>
|
||||
<script src="/static/js/hash-wasm.js"></script>
|
||||
<script src="/static/js/wasm_exec.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -18,14 +19,20 @@
|
|||
<h2 class="w300">Signup</h2>
|
||||
<p>Signup to {{ .identifier }}!</p>
|
||||
<p id="statusBox"></p>
|
||||
<input id="usernameBox" type="text" placeholder="Username">
|
||||
<input id="passwordBox" type="password" placeholder="Password">
|
||||
<img src="data:image/png;base64,{{ .captcha_image }}" alt="Captcha">
|
||||
<input id="captchaBox" type="text" placeholder="Captcha">
|
||||
<table id="inputContainer">
|
||||
<tr>
|
||||
<td><span id="inputNameBox">Username:</span></td>
|
||||
<td class="inputBox"><input id="usernameBox" type="text" placeholder="Username"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span id="inputPasswordBox">Password: </span></td>
|
||||
<td class="inputBox"><input id="passwordBox" type="password" placeholder="Password"><br></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<button id="signupButton">Signup</button><br><br>
|
||||
<p>Already have an account? If so, <a href="/login" id="loginButton">Login</a> instead!</p>
|
||||
<p>Please note that it's impossible to reset your password, do not forget it!</p>
|
||||
<button id="signupButton">Signup</button>
|
||||
<button onclick="toLogin();" id="loginButton" class="unimportant">Login</button>
|
||||
<br><br>
|
||||
<a href="{{ .privacy }}" id="privacyButton">Privacy & Terms</a>
|
||||
</div>
|
||||
<script type="text/javascript" src="../static/js/signup.js"></script>
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Tester - {{ .identifier }}</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="icon" href="/static/svg/favicon.svg">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css"/>
|
||||
<script src="/static/js/testapp.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p style="display: none;" id="client_id">{{ .client_id }}</p>
|
||||
<p style="display: none;" id="server_uri">{{ .server_uri }}</p>
|
||||
<img src="/static/img/background.png" class="background" alt="">
|
||||
<div class="inoutdiv">
|
||||
<h2 id="text">{{ .identifier }} Tester</h2>
|
||||
<button onclick="authorize()">Authorize</button>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|