diff --git a/src/api/oauth/refresh.ts b/src/api/oauth/refresh.ts
index 4357b28..277d848 100644
--- a/src/api/oauth/refresh.ts
+++ b/src/api/oauth/refresh.ts
@@ -16,6 +16,7 @@ import moment = require("moment");
// import { JWTExpDur } from "../../keys";
import RefreshToken from "../../models/refresh_token";
import { getEncryptionKey } from "../../helper/user_key";
+import { refreshTokenValidTime } from "../../config";
// TODO:
/*
@@ -27,8 +28,6 @@ legitimate client, one of them will present an invalidated refresh
token, which will inform the authorization server of the breach.
*/
-const refreshTokenValidTime = moment.duration(6, "month");
-
const RefreshTokenRoute = Stacker(
GetClientAuthMiddleware(false, false, true),
async (req: Request, res: Response) => {
diff --git a/src/api/user/index.ts b/src/api/user/index.ts
index 4d54321..d565e8c 100644
--- a/src/api/user/index.ts
+++ b/src/api/user/index.ts
@@ -1,11 +1,11 @@
import { Router } from "express";
import { GetAccount } from "./account";
import { GetContactInfos } from "./contact";
-import { GetJWTByUser } from "./jwt";
import Login from "./login";
import Register from "./register";
import { DeleteToken, GetToken } from "./token";
import TwoFactorRoute from "./twofactor";
+import OAuthRoute from "./oauth";
const UserRoute: Router = Router();
@@ -127,6 +127,6 @@ UserRoute.get("/account", GetAccount);
*/
UserRoute.get("/contact", GetContactInfos);
-UserRoute.get("/jwt", GetJWTByUser);
+UserRoute.use("/oauth", OAuthRoute);
export default UserRoute;
diff --git a/src/api/user/jwt.ts b/src/api/user/jwt.ts
deleted file mode 100644
index eb3bb82..0000000
--- a/src/api/user/jwt.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Request, Response } from "express";
-import Stacker from "../middlewares/stacker";
-import { GetUserMiddleware } from "../middlewares/user";
-import { URL } from "url";
-import Client from "../../models/client";
-import RequestError, { HttpStatusCode } from "../../helper/request_error";
-import { getAccessTokenJWT } from "../../helper/jwt";
-
-export const GetJWTByUser = Stacker(
- GetUserMiddleware(true, false),
- async (req: Request, res: Response) => {
- const { client_id, origin } = req.query as { [key: string]: string };
-
- const client = await Client.findOne({
- client_id,
- });
-
- const clientNotFoundError = new RequestError(
- "Client not found!",
- HttpStatusCode.BAD_REQUEST
- );
-
- if (!client) throw clientNotFoundError;
-
- const clientUrl = new URL(client.redirect_url);
-
- if (clientUrl.hostname !== origin) throw clientNotFoundError;
-
- const jwt = await getAccessTokenJWT({
- user: req.user,
- client: client,
- permissions: [],
- });
-
- res.json({ jwt });
- }
-);
diff --git a/src/api/user/oauth/_helper.ts b/src/api/user/oauth/_helper.ts
new file mode 100644
index 0000000..1fd6c84
--- /dev/null
+++ b/src/api/user/oauth/_helper.ts
@@ -0,0 +1,21 @@
+import RequestError, { HttpStatusCode } from "../../../helper/request_error";
+import Client, { IClient } from "../../../models/client";
+
+export async function getClientWithOrigin(client_id: string, origin: string) {
+ const client = await Client.findOne({
+ client_id,
+ });
+
+ const clientNotFoundError = new RequestError(
+ "Client not found!",
+ HttpStatusCode.BAD_REQUEST
+ );
+
+ if (!client) throw clientNotFoundError;
+
+ const clientUrl = new URL(client.redirect_url);
+
+ if (clientUrl.hostname !== origin) throw clientNotFoundError;
+
+ return client;
+}
diff --git a/src/api/user/oauth/index.ts b/src/api/user/oauth/index.ts
new file mode 100644
index 0000000..cab9ada
--- /dev/null
+++ b/src/api/user/oauth/index.ts
@@ -0,0 +1,12 @@
+import { Router } from "express";
+import { GetJWTByUser } from "./jwt";
+import { GetPermissionsForAuthRequest } from "./permissions";
+import { GetTokenByUser } from "./refresh_token";
+
+const router = Router();
+
+router.get("/jwt", GetJWTByUser);
+router.get("/permissions", GetPermissionsForAuthRequest);
+router.get("/refresh_token", GetTokenByUser);
+
+export default router;
diff --git a/src/api/user/oauth/jwt.ts b/src/api/user/oauth/jwt.ts
new file mode 100644
index 0000000..beca8b9
--- /dev/null
+++ b/src/api/user/oauth/jwt.ts
@@ -0,0 +1,25 @@
+import { Request, Response } from "express";
+import Stacker from "../../middlewares/stacker";
+import { GetUserMiddleware } from "../../middlewares/user";
+import { URL } from "url";
+import Client from "../../../models/client";
+import RequestError, { HttpStatusCode } from "../../../helper/request_error";
+import { getAccessTokenJWT } from "../../../helper/jwt";
+import { getClientWithOrigin } from "./_helper";
+
+export const GetJWTByUser = Stacker(
+ GetUserMiddleware(true, false),
+ async (req: Request, res: Response) => {
+ const { client_id, origin } = req.query as { [key: string]: string };
+
+ const client = await getClientWithOrigin(client_id, origin);
+
+ const jwt = await getAccessTokenJWT({
+ user: req.user,
+ client: client,
+ permissions: [],
+ });
+
+ res.json({ jwt });
+ }
+);
diff --git a/src/api/user/oauth/permissions.ts b/src/api/user/oauth/permissions.ts
new file mode 100644
index 0000000..395c4df
--- /dev/null
+++ b/src/api/user/oauth/permissions.ts
@@ -0,0 +1,38 @@
+import { Request, Response } from "express";
+import Stacker from "../../middlewares/stacker";
+import { GetUserMiddleware } from "../../middlewares/user";
+import { URL } from "url";
+import Client from "../../../models/client";
+import RequestError, { HttpStatusCode } from "../../../helper/request_error";
+import { randomBytes } from "crypto";
+import moment = require("moment");
+import RefreshToken from "../../../models/refresh_token";
+import { refreshTokenValidTime } from "../../../config";
+import { getClientWithOrigin } from "./_helper";
+import Permission from "../../../models/permissions";
+
+export const GetPermissionsForAuthRequest = Stacker(
+ GetUserMiddleware(true, false),
+ async (req: Request, res: Response) => {
+ const { client_id, origin, permissions } = req.query as {
+ [key: string]: string;
+ };
+
+ const client = await getClientWithOrigin(client_id, origin);
+
+ const perm = permissions.split(",").filter((e) => !!e);
+
+ const resolved = await Promise.all(
+ perm.map((p) => Permission.findById(p))
+ );
+
+ if (resolved.some((e) => e.grant_type !== "user")) {
+ throw new RequestError(
+ "Invalid Permission requested",
+ HttpStatusCode.BAD_REQUEST
+ );
+ }
+
+ res.json({ permissions: resolved });
+ }
+);
diff --git a/src/api/user/oauth/refresh_token.ts b/src/api/user/oauth/refresh_token.ts
new file mode 100644
index 0000000..4ff4cc4
--- /dev/null
+++ b/src/api/user/oauth/refresh_token.ts
@@ -0,0 +1,49 @@
+import { Request, Response } from "express";
+import Stacker from "../../middlewares/stacker";
+import { GetUserMiddleware } from "../../middlewares/user";
+import { URL } from "url";
+import Client from "../../../models/client";
+import RequestError, { HttpStatusCode } from "../../../helper/request_error";
+import { randomBytes } from "crypto";
+import moment = require("moment");
+import RefreshToken from "../../../models/refresh_token";
+import { refreshTokenValidTime } from "../../../config";
+import { getClientWithOrigin } from "./_helper";
+import Permission from "../../../models/permissions";
+
+export const GetTokenByUser = Stacker(
+ GetUserMiddleware(true, false),
+ async (req: Request, res: Response) => {
+ const { client_id, origin, permissions } = req.query as {
+ [key: string]: string;
+ };
+
+ const client = await getClientWithOrigin(client_id, origin);
+
+ const perm = permissions.split(",").filter((e) => !!e);
+
+ const resolved = await Promise.all(
+ perm.map((p) => Permission.findById(p))
+ );
+
+ if (resolved.some((e) => e.grant_type !== "user")) {
+ throw new RequestError(
+ "Invalid Permission requested",
+ HttpStatusCode.BAD_REQUEST
+ );
+ }
+
+ let token = RefreshToken.new({
+ user: req.user._id,
+ client: client._id,
+ permissions: resolved.map((e) => e._id),
+ token: randomBytes(16).toString("hex"),
+ valid: true,
+ validTill: moment().add(refreshTokenValidTime).toDate(),
+ });
+
+ await RefreshToken.save(token);
+
+ res.json({ token });
+ }
+);
diff --git a/src/config.ts b/src/config.ts
index fa5f1f0..956742c 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -1,8 +1,9 @@
import { parse } from "@hibas123/config";
import { Logging } from "@hibas123/nodelogging";
import * as dotenv from "dotenv";
-import { readFileSync } from "fs";
-import * as ini from "ini";
+import moment = require("moment");
+
+export const refreshTokenValidTime = moment.duration(6, "month");
dotenv.config();
diff --git a/src/views/views.ts b/src/views/views.ts
index f8acc67..6f18d3d 100644
--- a/src/views/views.ts
+++ b/src/views/views.ts
@@ -40,13 +40,13 @@ ViewRouter.get("/register", (req, res) => {
ViewRouter.use(
"/login",
addCache,
- ServeStatic("./views_repo/build/login", { cacheControl: false })
+ ServeStatic("./views_repo/build/Login", { cacheControl: false })
);
ViewRouter.use(
"/user",
addCache,
- ServeStatic("./views_repo/build/user", { cacheControl: false })
+ ServeStatic("./views_repo/build/User", { cacheControl: false })
);
ViewRouter.get("/code", (req, res) => {
@@ -69,9 +69,15 @@ ViewRouter.get(
ViewRouter.get("/auth", GetAuthRoute(true));
-ViewRouter.get("/popup", UserMiddleware, (req, res) => {
- res.send(GetPopupPage(req.__));
-});
+ViewRouter.use(
+ "/popup",
+ addCache,
+ ServeStatic("./views_repo/build/Popup", { cacheControl: false })
+);
+
+// ViewRouter.get("/popup", UserMiddleware, (req, res) => {
+// res.send(GetPopupPage(req.__));
+// });
// if (config.core.dev) {
// const logo =
diff --git a/views/src/login/login.hbs b/views/src/login/login.hbs
deleted file mode 100644
index 2988f8c..0000000
--- a/views/src/login/login.hbs
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
- {{i18n "Login"}}
-
-
-
-
-
-
- {{!--
- {{i18n "Login"}}
-
-
- --}}
-
-
-
\ No newline at end of file
diff --git a/views/src/login/login.js b/views/src/login/login.js
deleted file mode 100644
index 89613d0..0000000
--- a/views/src/login/login.js
+++ /dev/null
@@ -1,166 +0,0 @@
-import sha from "sha512";
-import { setCookie, getCookie } from "cookie";
-import "inputs";
-
-const loader = document.getElementById("loader");
-const container = document.getElementById("container");
-const usernameinput = document.getElementById("username");
-const usernamegroup = document.getElementById("usernamegroup");
-const uerrorfield = document.getElementById("uerrorfield");
-const passwordinput = document.getElementById("password");
-const passwordgroup = document.getElementById("passwordgroup");
-const perrorfield = document.getElementById("perrorfield");
-const nextbutton = document.getElementById("nextbutton");
-const loginbutton = document.getElementById("loginbutton");
-
-let username;
-let salt;
-
-usernameinput.focus();
-
-const loading = () => {
- container.style.filter = "blur(2px)";
- loader.style.display = "";
-};
-
-const loading_fin = () => {
- container.style.filter = "";
- loader.style.display = "none";
-};
-loading_fin();
-
-usernameinput.onkeydown = (e) => {
- var keycode = e.keyCode ? e.keyCode : e.which;
- if (keycode === 13) nextbutton.click();
- clearError(uerrorfield);
-};
-
-nextbutton.onclick = async () => {
- loading();
- username = usernameinput.value;
- try {
- let res = await fetch(
- "/api/user/login?type=username&username=" + username,
- {
- method: "POST",
- }
- )
- .then((e) => {
- if (e.status !== 200) throw new Error(e.statusText);
- return e.json();
- })
- .then((data) => {
- if (data.error) {
- return Promise.reject(new Error(data.error));
- }
- return data;
- });
- salt = res.salt;
- usernamegroup.classList.add("invisible");
- passwordgroup.classList.remove("invisible");
- passwordinput.focus();
- } catch (e) {
- showError(uerrorfield, e.message);
- }
- loading_fin();
-};
-
-passwordinput.onkeydown = (e) => {
- var keycode = e.keyCode ? e.keyCode : e.which;
- if (keycode === 13) loginbutton.click();
- clearError(perrorfield);
-};
-
-loginbutton.onclick = async () => {
- loading();
- let pw = sha(salt + passwordinput.value);
- try {
- let { login, special, tfa } = await fetch(
- "/api/user/login?type=password",
- {
- method: "POST",
- body: JSON.stringify({
- username: usernameinput.value,
- password: pw,
- }),
- headers: {
- "content-type": "application/json",
- },
- }
- )
- .then((e) => {
- if (e.status !== 200) throw new Error(e.statusText);
- return e.json();
- })
- .then((data) => {
- if (data.error) {
- return Promise.reject(new Error(data.error));
- }
- return data;
- });
-
- setCookie("login", login.token, new Date(login.expires).toUTCString());
- setCookie(
- "special",
- special.token,
- new Date(special.expires).toUTCString()
- );
- let d = new Date();
- d.setTime(d.getTime() + 30 * 24 * 60 * 60 * 1000); //Keep the username 30 days
- setCookie("username", username, d.toUTCString());
- let url = new URL(window.location.href);
- let state = url.searchParams.get("state");
- let red = "/";
-
- if (tfa) twofactor(tfa);
- else {
- if (state) {
- let base64 = url.searchParams.get("base64");
- if (base64) red = atob(state);
- else red = state;
- }
- window.location.href = red;
- }
- } catch (e) {
- passwordinput.value = "";
- showError(perrorfield, e.message);
- }
- loading_fin();
-};
-
-function clearError(field) {
- field.innerText = "";
- field.classList.add("invisible");
-}
-
-function showError(field, error) {
- field.innerText = error;
- field.classList.remove("invisible");
-}
-
-username = getCookie("username");
-if (username) {
- usernameinput.value = username;
-
- var evt = document.createEvent("HTMLEvents");
- evt.initEvent("change", false, true);
- usernameinput.dispatchEvent(evt);
-}
-
-function twofactor(tfa) {
- let list = tfa
- .map((entry) => {
- switch (entry) {
- case 0: // OTC
- return "Authenticator App";
- case 1: // BACKUP
- return "Backup Key";
- }
- return undefined;
- })
- .filter((e) => e !== undefined)
- .reduce((p, c) => p + `${c}`, "");
-
- let tfl = document.getElementById("tflist");
- tfl.innerHTML = list;
-}
diff --git a/views/src/login/login.scss b/views/src/login/login.scss
deleted file mode 100644
index f7f6ee8..0000000
--- a/views/src/login/login.scss
+++ /dev/null
@@ -1,132 +0,0 @@
-@import "@material/button/mdc-button";
-@import "inputs";
-@import "style";
-
-.spanned-btn {
- width: 100%;
- background: $primary !important; // text-shadow: 1px 1px 0 rgba(39, 110, 204, .5);
-}
-
-* {
- box-sizing: border-box;
-}
-
-body {
- font-family: Helvetica;
- background: #eee;
- -webkit-font-smoothing: antialiased;
-}
-
-header {
- text-align: center;
- margin-top: 4em;
-}
-
-h1,
-h3 {
- font-weight: 300;
-}
-
-h1 {
- color: #636363;
-}
-
-h3 {
- color: $primary;
-}
-
-form {
- max-width: 380px;
- margin: 4em auto;
- padding: 3em 2em 2em 2em;
- background: #fafafa;
- border: 1px solid #ebebeb;
- box-shadow: rgba(0, 0, 0, 0.14902) 0px 1px 1px 0px,
- rgba(0, 0, 0, 0.09804) 0px 1px 2px 0px;
- position: relative;
-}
-
-.loader_box {
- width: 64px;
- height: 64px;
- margin: auto;
- position: absolute;
- top: 0;
- left: 0;
- bottom: 0;
- right: 0;
-}
-
-.loader {
- display: inline-block;
- position: relative;
- z-index: 100;
-}
-.loader:after {
- content: " ";
- display: block;
- width: 46px;
- height: 46px;
- margin: 1px;
- border-radius: 50%;
- border: 5px solid #000000;
- border-color: #000000 transparent #000000 transparent;
- animation: loader 1.2s linear infinite;
-}
-@keyframes loader {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(360deg);
- }
-}
-
-footer {
- text-align: center;
-}
-
-footer p {
- color: #888;
- font-size: 13px;
- letter-spacing: 0.4px;
-}
-
-footer a {
- color: $primary;
- text-decoration: none;
- transition: all 0.2s ease;
-}
-
-footer a:hover {
- color: #666;
- text-decoration: underline;
-}
-
-footer img {
- width: 80px;
- transition: all 0.2s ease;
-}
-
-footer img:hover {
- opacity: 0.83;
-}
-
-footer img:focus,
-footer a:focus {
- outline: none;
-}
-
-.invisible {
- display: none;
-}
-
-.errorColor {
- background: $error !important;
-}
-
-.error {
- color: $error;
- margin-top: 5px;
- font-size: 13px;
-}
diff --git a/views/src/login/login.tsx b/views/src/login/login.tsx
deleted file mode 100644
index 76fde9d..0000000
--- a/views/src/login/login.tsx
+++ /dev/null
@@ -1,434 +0,0 @@
-import { h, Component, render } from "preact";
-import "inputs";
-import "./u2f-api-polyfill";
-
-import sha from "sha512";
-import { setCookie, getCookie } from "cookie";
-
-let appname = "test";
-
-function Loader() {
- return (
-
- );
-}
-
-class Username extends Component<
- { username: string; onNext: (username: string, salt: string) => void },
- { error: string; loading: boolean }
-> {
- username_input: HTMLInputElement;
- constructor() {
- super();
- this.state = { error: undefined, loading: false };
- }
-
- async onClick() {
- this.setState({ loading: true });
- try {
- let res = await fetch(
- "/api/user/login?type=username&username=" +
- this.username_input.value,
- {
- method: "POST",
- }
- )
- .then((e) => {
- if (e.status !== 200) throw new Error(e.statusText);
- return e.json();
- })
- .then((data) => {
- if (data.error) {
- return Promise.reject(new Error(data.error));
- }
- return data;
- });
- let salt = res.salt;
- this.props.onNext(this.username_input.value, salt);
- } catch (err) {
- this.setState({
- error: err.message,
- });
- }
- this.setState({ loading: false });
- }
-
- render() {
- if (this.state.loading) return ;
- return (
-
-
-
{
- let k = e.keyCode | e.which;
- if (k === 13) this.onClick();
- this.setState({ error: undefined });
- }}
- type="text"
- value={
- this.username_input
- ? this.username_input.value
- : this.props.username
- }
- autofocus
- ref={(elm) => (elm ? (this.username_input = elm) : undefined)}
- />
-
-
-
- {this.state.error ? (
-
{this.state.error}
- ) : undefined}
-
-
-
- );
- }
-}
-
-enum TFATypes {
- OTC,
- BACKUP_CODE,
- YUBI_KEY,
- APP_ALLOW,
-}
-
-interface TwoFactors {
- id: string;
- name: string;
- type: TFATypes;
-}
-
-class Password extends Component<
- {
- username: string;
- salt: string;
- onNext: (login: Token, special: Token, tfa: TwoFactors[]) => void;
- },
- { error: string; loading: boolean }
-> {
- password_input: HTMLInputElement;
- constructor() {
- super();
- this.state = { error: undefined, loading: false };
- }
-
- async onClick() {
- this.setState({
- loading: true,
- });
-
- try {
- let pw = sha(this.props.salt + this.password_input.value);
- let { login, special, tfa } = await fetch(
- "/api/user/login?type=password",
- {
- method: "POST",
- body: JSON.stringify({
- username: this.props.username,
- password: pw,
- }),
- headers: {
- "content-type": "application/json",
- },
- }
- )
- .then((e) => {
- if (e.status !== 200) throw new Error(e.statusText);
- return e.json();
- })
- .then((data) => {
- if (data.error) {
- return Promise.reject(new Error(data.error));
- }
- return data;
- });
- this.props.onNext(login, special, tfa);
- } catch (err) {
- this.setState({ error: err.messagae });
- }
- this.setState({ loading: false });
- }
-
- render() {
- if (this.state.loading) return ;
- return (
-
-
-
{
- let k = e.keyCode | e.which;
- if (k === 13) this.onClick();
- this.setState({ error: undefined });
- }}
- type="password"
- ref={(elm: HTMLInputElement) => {
- if (elm) {
- this.password_input = elm;
- setTimeout(() => elm.focus(), 200);
- // elm.focus();
- }
- }}
- />
-
-
-
- {this.state.error ? (
-
{this.state.error}
- ) : undefined}
-
-
-
- );
- }
-}
-
-class TwoFactor extends Component<
- { twofactors: TwoFactors[]; next: (id: string, type: TFATypes) => void },
- {}
-> {
- render() {
- let tfs = this.props.twofactors.map((fac) => {
- let name: string;
- switch (fac.type) {
- case TFATypes.OTC:
- name = "Authenticator";
- break;
- case TFATypes.BACKUP_CODE:
- name = "Backup code";
- break;
- case TFATypes.APP_ALLOW:
- name = "Use App: %s";
- break;
- case TFATypes.YUBI_KEY:
- name = "Use Yubikey: %s";
- break;
- }
-
- name = name.replace("%s", fac.name ? fac.name : "");
-
- return (
- {
- console.log("Click on Solution");
- this.props.next(fac.id, fac.type);
- }}
- >
- {name}
-
- );
- });
- return (
-
- );
- }
-}
-
-// class TFA_YubiKey extends Component<{ id: string, login: Token, special: Token, next: (login: Token, special: Token) => void }, {}> {
-// render() {
-
-// }
-// }
-
-enum Page {
- username,
- password,
- twofactor,
- yubikey,
-}
-
-interface Token {
- token: string;
- expires: string;
-}
-
-async function apiRequest(
- endpoint: string,
- method: "GET" | "POST" | "DELETE" | "PUT" = "GET",
- body: string = undefined
-) {
- return fetch(endpoint, {
- method,
- body,
- credentials: "same-origin",
- headers: {
- "content-type": "application/json",
- },
- })
- .then((e) => {
- if (e.status !== 200) throw new Error(e.statusText);
- return e.json();
- })
- .then((data) => {
- if (data.error) {
- return Promise.reject(new Error(data.error));
- }
- return data;
- });
-}
-
-class App extends Component<
- {},
- {
- page: Page;
- username: string;
- salt: string;
- twofactor: TwoFactors[];
- twofactor_id: string;
- }
-> {
- login: Token;
- special: Token;
- constructor() {
- super();
- this.state = {
- page: Page.username,
- username: getCookie("username"),
- salt: undefined,
- twofactor: [],
- twofactor_id: null,
- };
- }
-
- setCookies() {
- setCookie(
- "login",
- this.login.token,
- new Date(this.login.expires).toUTCString()
- );
- setCookie(
- "special",
- this.special.token,
- new Date(this.special.expires).toUTCString()
- );
- }
-
- finish() {
- this.setCookies();
- let d = new Date();
- d.setTime(d.getTime() + 30 * 24 * 60 * 60 * 1000); //Keep the username 30 days
- setCookie("username", this.state.username, d.toUTCString());
- let url = new URL(window.location.href);
- let state = url.searchParams.get("state");
- let red = "/";
-
- if (state) {
- let base64 = url.searchParams.get("base64");
- if (base64) red = atob(state);
- else red = state;
- }
- window.location.href = red;
- }
-
- render() {
- let cont;
- switch (this.state.page) {
- case Page.username:
- cont = (
- {
- this.setState({ username, salt, page: Page.password });
- localStorage.setItem("username", username);
- }}
- />
- );
- break;
- case Page.password:
- cont = (
- {
- this.login = login;
- this.special = special;
- this.setCookies();
-
- if (!twofactor) {
- this.finish();
- } else {
- this.setState({ twofactor, page: Page.twofactor });
- }
- }}
- />
- );
- break;
- case Page.twofactor:
- cont = (
- {
- if (type === TFATypes.YUBI_KEY) {
- let { request } = await apiRequest(
- "/api/user/twofactor/yubikey",
- "GET"
- );
- console.log(request);
- (window as any).u2f.sign(
- request.appId,
- [request.challenge],
- [request],
- async (response) => {
- let res = await apiRequest(
- "/api/user/twofactor/yubikey",
- "PUT",
- JSON.stringify({ response })
- );
- if (res.success) {
- this.login.expires = res.login_exp;
- this.special.expires = res.special_exp;
- this.finish();
- }
- }
- );
- }
- }}
- />
- );
- break;
- // case Page.yubikey:
- // cont = {
- // this.login = login;
- // this.special = special;
- // this.finish()
- // }} />
- // break;
- }
- return (
-
- );
- }
-}
-
-document.addEventListener(
- "DOMContentLoaded",
- function () {
- render(, document.body.querySelector("#content"));
- },
- false
-);
diff --git a/views/src/login/u2f-api-polyfill.js b/views/src/login/u2f-api-polyfill.js
deleted file mode 100644
index cb372bd..0000000
--- a/views/src/login/u2f-api-polyfill.js
+++ /dev/null
@@ -1,844 +0,0 @@
-//Copyright 2014-2015 Google Inc. All rights reserved.
-
-//Use of this source code is governed by a BSD-style
-//license that can be found in the LICENSE file or at
-//https://developers.google.com/open-source/licenses/bsd
-
-// NOTE FROM MAINTAINER: This file is copied from google/u2f-ref-code with as
-// few alterations as possible. Any changes that were necessary are annotated
-// with "NECESSARY CHANGE". These changes, as well as this note, should be
-// preserved when updating this file from the source.
-
-/**
- * @fileoverview The U2F api.
- */
-"use strict";
-
-// NECESSARY CHANGE: wrap the whole file in a closure
-(function () {
- // NECESSARY CHANGE: detect UA to avoid clobbering other browser's U2F API.
- var isChrome =
- "chrome" in window && window.navigator.userAgent.indexOf("Edge") < 0;
- if ("u2f" in window || !isChrome) {
- return;
- }
-
- /**
- * Namespace for the U2F api.
- * @type {Object}
- */
- // NECESSARY CHANGE: define the window.u2f API.
- var u2f = (window.u2f = {});
-
- /**
- * FIDO U2F Javascript API Version
- * @number
- */
- var js_api_version;
-
- /**
- * The U2F extension id
- * @const {string}
- */
- // The Chrome packaged app extension ID.
- // Uncomment this if you want to deploy a server instance that uses
- // the package Chrome app and does not require installing the U2F Chrome extension.
- u2f.EXTENSION_ID = "kmendfapggjehodndflmmgagdbamhnfd";
- // The U2F Chrome extension ID.
- // Uncomment this if you want to deploy a server instance that uses
- // the U2F Chrome extension to authenticate.
- // u2f.EXTENSION_ID = 'pfboblefjcgdjicmnffhdgionmgcdmne';
-
- /**
- * Message types for messsages to/from the extension
- * @const
- * @enum {string}
- */
- u2f.MessageTypes = {
- U2F_REGISTER_REQUEST: "u2f_register_request",
- U2F_REGISTER_RESPONSE: "u2f_register_response",
- U2F_SIGN_REQUEST: "u2f_sign_request",
- U2F_SIGN_RESPONSE: "u2f_sign_response",
- U2F_GET_API_VERSION_REQUEST: "u2f_get_api_version_request",
- U2F_GET_API_VERSION_RESPONSE: "u2f_get_api_version_response",
- };
-
- /**
- * Response status codes
- * @const
- * @enum {number}
- */
- u2f.ErrorCodes = {
- OK: 0,
- OTHER_ERROR: 1,
- BAD_REQUEST: 2,
- CONFIGURATION_UNSUPPORTED: 3,
- DEVICE_INELIGIBLE: 4,
- TIMEOUT: 5,
- };
-
- /**
- * A message for registration requests
- * @typedef {{
- * type: u2f.MessageTypes,
- * appId: ?string,
- * timeoutSeconds: ?number,
- * requestId: ?number
- * }}
- */
- u2f.U2fRequest;
-
- /**
- * A message for registration responses
- * @typedef {{
- * type: u2f.MessageTypes,
- * responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse),
- * requestId: ?number
- * }}
- */
- u2f.U2fResponse;
-
- /**
- * An error object for responses
- * @typedef {{
- * errorCode: u2f.ErrorCodes,
- * errorMessage: ?string
- * }}
- */
- u2f.Error;
-
- /**
- * Data object for a single sign request.
- * @typedef {enum {BLUETOOTH_RADIO, BLUETOOTH_LOW_ENERGY, USB, NFC, USB_INTERNAL}}
- */
- u2f.Transport;
-
- /**
- * Data object for a single sign request.
- * @typedef {Array}
- */
- u2f.Transports;
-
- /**
- * Data object for a single sign request.
- * @typedef {{
- * version: string,
- * challenge: string,
- * keyHandle: string,
- * appId: string
- * }}
- */
- u2f.SignRequest;
-
- /**
- * Data object for a sign response.
- * @typedef {{
- * keyHandle: string,
- * signatureData: string,
- * clientData: string
- * }}
- */
- u2f.SignResponse;
-
- /**
- * Data object for a registration request.
- * @typedef {{
- * version: string,
- * challenge: string
- * }}
- */
- u2f.RegisterRequest;
-
- /**
- * Data object for a registration response.
- * @typedef {{
- * version: string,
- * keyHandle: string,
- * transports: Transports,
- * appId: string
- * }}
- */
- u2f.RegisterResponse;
-
- /**
- * Data object for a registered key.
- * @typedef {{
- * version: string,
- * keyHandle: string,
- * transports: ?Transports,
- * appId: ?string
- * }}
- */
- u2f.RegisteredKey;
-
- /**
- * Data object for a get API register response.
- * @typedef {{
- * js_api_version: number
- * }}
- */
- u2f.GetJsApiVersionResponse;
-
- //Low level MessagePort API support
-
- /**
- * Sets up a MessagePort to the U2F extension using the
- * available mechanisms.
- * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
- */
- u2f.getMessagePort = function (callback) {
- if (typeof chrome != "undefined" && chrome.runtime) {
- // The actual message here does not matter, but we need to get a reply
- // for the callback to run. Thus, send an empty signature request
- // in order to get a failure response.
- var msg = {
- type: u2f.MessageTypes.U2F_SIGN_REQUEST,
- signRequests: [],
- };
- chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function () {
- if (!chrome.runtime.lastError) {
- // We are on a whitelisted origin and can talk directly
- // with the extension.
- u2f.getChromeRuntimePort_(callback);
- } else {
- // chrome.runtime was available, but we couldn't message
- // the extension directly, use iframe
- u2f.getIframePort_(callback);
- }
- });
- } else if (u2f.isAndroidChrome_()) {
- u2f.getAuthenticatorPort_(callback);
- } else if (u2f.isIosChrome_()) {
- u2f.getIosPort_(callback);
- } else {
- // chrome.runtime was not available at all, which is normal
- // when this origin doesn't have access to any extensions.
- u2f.getIframePort_(callback);
- }
- };
-
- /**
- * Detect chrome running on android based on the browser's useragent.
- * @private
- */
- u2f.isAndroidChrome_ = function () {
- var userAgent = navigator.userAgent;
- return (
- userAgent.indexOf("Chrome") != -1 && userAgent.indexOf("Android") != -1
- );
- };
-
- /**
- * Detect chrome running on iOS based on the browser's platform.
- * @private
- */
- u2f.isIosChrome_ = function () {
- return ["iPhone", "iPad", "iPod"].indexOf(navigator.platform) > -1;
- };
-
- /**
- * Connects directly to the extension via chrome.runtime.connect.
- * @param {function(u2f.WrappedChromeRuntimePort_)} callback
- * @private
- */
- u2f.getChromeRuntimePort_ = function (callback) {
- var port = chrome.runtime.connect(u2f.EXTENSION_ID, {
- includeTlsChannelId: true,
- });
- setTimeout(function () {
- callback(new u2f.WrappedChromeRuntimePort_(port));
- }, 0);
- };
-
- /**
- * Return a 'port' abstraction to the Authenticator app.
- * @param {function(u2f.WrappedAuthenticatorPort_)} callback
- * @private
- */
- u2f.getAuthenticatorPort_ = function (callback) {
- setTimeout(function () {
- callback(new u2f.WrappedAuthenticatorPort_());
- }, 0);
- };
-
- /**
- * Return a 'port' abstraction to the iOS client app.
- * @param {function(u2f.WrappedIosPort_)} callback
- * @private
- */
- u2f.getIosPort_ = function (callback) {
- setTimeout(function () {
- callback(new u2f.WrappedIosPort_());
- }, 0);
- };
-
- /**
- * A wrapper for chrome.runtime.Port that is compatible with MessagePort.
- * @param {Port} port
- * @constructor
- * @private
- */
- u2f.WrappedChromeRuntimePort_ = function (port) {
- this.port_ = port;
- };
-
- /**
- * Format and return a sign request compliant with the JS API version supported by the extension.
- * @param {Array} signRequests
- * @param {number} timeoutSeconds
- * @param {number} reqId
- * @return {Object}
- */
- u2f.formatSignRequest_ = function (
- appId,
- challenge,
- registeredKeys,
- timeoutSeconds,
- reqId
- ) {
- if (js_api_version === undefined || js_api_version < 1.1) {
- // Adapt request to the 1.0 JS API
- var signRequests = [];
- for (var i = 0; i < registeredKeys.length; i++) {
- signRequests[i] = {
- version: registeredKeys[i].version,
- challenge: challenge,
- keyHandle: registeredKeys[i].keyHandle,
- appId: appId,
- };
- }
- return {
- type: u2f.MessageTypes.U2F_SIGN_REQUEST,
- signRequests: signRequests,
- timeoutSeconds: timeoutSeconds,
- requestId: reqId,
- };
- }
- // JS 1.1 API
- return {
- type: u2f.MessageTypes.U2F_SIGN_REQUEST,
- appId: appId,
- challenge: challenge,
- registeredKeys: registeredKeys,
- timeoutSeconds: timeoutSeconds,
- requestId: reqId,
- };
- };
-
- /**
- * Format and return a register request compliant with the JS API version supported by the extension..
- * @param {Array} signRequests
- * @param {Array} signRequests
- * @param {number} timeoutSeconds
- * @param {number} reqId
- * @return {Object}
- */
- u2f.formatRegisterRequest_ = function (
- appId,
- registeredKeys,
- registerRequests,
- timeoutSeconds,
- reqId
- ) {
- if (js_api_version === undefined || js_api_version < 1.1) {
- // Adapt request to the 1.0 JS API
- for (var i = 0; i < registerRequests.length; i++) {
- registerRequests[i].appId = appId;
- }
- var signRequests = [];
- for (var i = 0; i < registeredKeys.length; i++) {
- signRequests[i] = {
- version: registeredKeys[i].version,
- challenge: registerRequests[0],
- keyHandle: registeredKeys[i].keyHandle,
- appId: appId,
- };
- }
- return {
- type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
- signRequests: signRequests,
- registerRequests: registerRequests,
- timeoutSeconds: timeoutSeconds,
- requestId: reqId,
- };
- }
- // JS 1.1 API
- return {
- type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
- appId: appId,
- registerRequests: registerRequests,
- registeredKeys: registeredKeys,
- timeoutSeconds: timeoutSeconds,
- requestId: reqId,
- };
- };
-
- /**
- * Posts a message on the underlying channel.
- * @param {Object} message
- */
- u2f.WrappedChromeRuntimePort_.prototype.postMessage = function (message) {
- this.port_.postMessage(message);
- };
-
- /**
- * Emulates the HTML 5 addEventListener interface. Works only for the
- * onmessage event, which is hooked up to the chrome.runtime.Port.onMessage.
- * @param {string} eventName
- * @param {function({data: Object})} handler
- */
- u2f.WrappedChromeRuntimePort_.prototype.addEventListener = function (
- eventName,
- handler
- ) {
- var name = eventName.toLowerCase();
- if (name == "message" || name == "onmessage") {
- this.port_.onMessage.addListener(function (message) {
- // Emulate a minimal MessageEvent object
- handler({ data: message });
- });
- } else {
- console.error("WrappedChromeRuntimePort only supports onMessage");
- }
- };
-
- /**
- * Wrap the Authenticator app with a MessagePort interface.
- * @constructor
- * @private
- */
- u2f.WrappedAuthenticatorPort_ = function () {
- this.requestId_ = -1;
- this.requestObject_ = null;
- };
-
- /**
- * Launch the Authenticator intent.
- * @param {Object} message
- */
- u2f.WrappedAuthenticatorPort_.prototype.postMessage = function (message) {
- var intentUrl =
- u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ +
- ";S.request=" +
- encodeURIComponent(JSON.stringify(message)) +
- ";end";
- document.location = intentUrl;
- };
-
- /**
- * Tells what type of port this is.
- * @return {String} port type
- */
- u2f.WrappedAuthenticatorPort_.prototype.getPortType = function () {
- return "WrappedAuthenticatorPort_";
- };
-
- /**
- * Emulates the HTML 5 addEventListener interface.
- * @param {string} eventName
- * @param {function({data: Object})} handler
- */
- u2f.WrappedAuthenticatorPort_.prototype.addEventListener = function (
- eventName,
- handler
- ) {
- var name = eventName.toLowerCase();
- if (name == "message") {
- var self = this;
- /* Register a callback to that executes when
- * chrome injects the response. */
- window.addEventListener(
- "message",
- self.onRequestUpdate_.bind(self, handler),
- false
- );
- } else {
- console.error("WrappedAuthenticatorPort only supports message");
- }
- };
-
- /**
- * Callback invoked when a response is received from the Authenticator.
- * @param function({data: Object}) callback
- * @param {Object} message message Object
- */
- u2f.WrappedAuthenticatorPort_.prototype.onRequestUpdate_ = function (
- callback,
- message
- ) {
- var messageObject = JSON.parse(message.data);
- var intentUrl = messageObject["intentURL"];
-
- var errorCode = messageObject["errorCode"];
- var responseObject = null;
- if (messageObject.hasOwnProperty("data")) {
- responseObject = /** @type {Object} */ (JSON.parse(
- messageObject["data"]
- ));
- }
-
- callback({ data: responseObject });
- };
-
- /**
- * Base URL for intents to Authenticator.
- * @const
- * @private
- */
- u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ =
- "intent:#Intent;action=com.google.android.apps.authenticator.AUTHENTICATE";
-
- /**
- * Wrap the iOS client app with a MessagePort interface.
- * @constructor
- * @private
- */
- u2f.WrappedIosPort_ = function () {};
-
- /**
- * Launch the iOS client app request
- * @param {Object} message
- */
- u2f.WrappedIosPort_.prototype.postMessage = function (message) {
- var str = JSON.stringify(message);
- var url = "u2f://auth?" + encodeURI(str);
- location.replace(url);
- };
-
- /**
- * Tells what type of port this is.
- * @return {String} port type
- */
- u2f.WrappedIosPort_.prototype.getPortType = function () {
- return "WrappedIosPort_";
- };
-
- /**
- * Emulates the HTML 5 addEventListener interface.
- * @param {string} eventName
- * @param {function({data: Object})} handler
- */
- u2f.WrappedIosPort_.prototype.addEventListener = function (
- eventName,
- handler
- ) {
- var name = eventName.toLowerCase();
- if (name !== "message") {
- console.error("WrappedIosPort only supports message");
- }
- };
-
- /**
- * Sets up an embedded trampoline iframe, sourced from the extension.
- * @param {function(MessagePort)} callback
- * @private
- */
- u2f.getIframePort_ = function (callback) {
- // Create the iframe
- var iframeOrigin = "chrome-extension://" + u2f.EXTENSION_ID;
- var iframe = document.createElement("iframe");
- iframe.src = iframeOrigin + "/u2f-comms.html";
- iframe.setAttribute("style", "display:none");
- document.body.appendChild(iframe);
-
- var channel = new MessageChannel();
- var ready = function (message) {
- if (message.data == "ready") {
- channel.port1.removeEventListener("message", ready);
- callback(channel.port1);
- } else {
- console.error('First event on iframe port was not "ready"');
- }
- };
- channel.port1.addEventListener("message", ready);
- channel.port1.start();
-
- iframe.addEventListener("load", function () {
- // Deliver the port to the iframe and initialize
- iframe.contentWindow.postMessage("init", iframeOrigin, [
- channel.port2,
- ]);
- });
- };
-
- //High-level JS API
-
- /**
- * Default extension response timeout in seconds.
- * @const
- */
- u2f.EXTENSION_TIMEOUT_SEC = 30;
-
- /**
- * A singleton instance for a MessagePort to the extension.
- * @type {MessagePort|u2f.WrappedChromeRuntimePort_}
- * @private
- */
- u2f.port_ = null;
-
- /**
- * Callbacks waiting for a port
- * @type {Array}
- * @private
- */
- u2f.waitingForPort_ = [];
-
- /**
- * A counter for requestIds.
- * @type {number}
- * @private
- */
- u2f.reqCounter_ = 0;
-
- /**
- * A map from requestIds to client callbacks
- * @type {Object.}
- * @private
- */
- u2f.callbackMap_ = {};
-
- /**
- * Creates or retrieves the MessagePort singleton to use.
- * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
- * @private
- */
- u2f.getPortSingleton_ = function (callback) {
- if (u2f.port_) {
- callback(u2f.port_);
- } else {
- if (u2f.waitingForPort_.length == 0) {
- u2f.getMessagePort(function (port) {
- u2f.port_ = port;
- u2f.port_.addEventListener(
- "message",
- /** @type {function(Event)} */ (u2f.responseHandler_)
- );
-
- // Careful, here be async callbacks. Maybe.
- while (u2f.waitingForPort_.length)
- u2f.waitingForPort_.shift()(u2f.port_);
- });
- }
- u2f.waitingForPort_.push(callback);
- }
- };
-
- /**
- * Handles response messages from the extension.
- * @param {MessageEvent.} message
- * @private
- */
- u2f.responseHandler_ = function (message) {
- var response = message.data;
- var reqId = response["requestId"];
- if (!reqId || !u2f.callbackMap_[reqId]) {
- console.error("Unknown or missing requestId in response.");
- return;
- }
- var cb = u2f.callbackMap_[reqId];
- delete u2f.callbackMap_[reqId];
- cb(response["responseData"]);
- };
-
- /**
- * Dispatches an array of sign requests to available U2F tokens.
- * If the JS API version supported by the extension is unknown, it first sends a
- * message to the extension to find out the supported API version and then it sends
- * the sign request.
- * @param {string=} appId
- * @param {string=} challenge
- * @param {Array} registeredKeys
- * @param {function((u2f.Error|u2f.SignResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
- u2f.sign = function (
- appId,
- challenge,
- registeredKeys,
- callback,
- opt_timeoutSeconds
- ) {
- if (js_api_version === undefined) {
- // Send a message to get the extension to JS API version, then send the actual sign request.
- u2f.getApiVersion(function (response) {
- js_api_version =
- response["js_api_version"] === undefined
- ? 0
- : response["js_api_version"];
- console.log("Extension JS API Version: ", js_api_version);
- u2f.sendSignRequest(
- appId,
- challenge,
- registeredKeys,
- callback,
- opt_timeoutSeconds
- );
- });
- } else {
- // We know the JS API version. Send the actual sign request in the supported API version.
- u2f.sendSignRequest(
- appId,
- challenge,
- registeredKeys,
- callback,
- opt_timeoutSeconds
- );
- }
- };
-
- /**
- * Dispatches an array of sign requests to available U2F tokens.
- * @param {string=} appId
- * @param {string=} challenge
- * @param {Array} registeredKeys
- * @param {function((u2f.Error|u2f.SignResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
- u2f.sendSignRequest = function (
- appId,
- challenge,
- registeredKeys,
- callback,
- opt_timeoutSeconds
- ) {
- u2f.getPortSingleton_(function (port) {
- var reqId = ++u2f.reqCounter_;
- u2f.callbackMap_[reqId] = callback;
- var timeoutSeconds =
- typeof opt_timeoutSeconds !== "undefined"
- ? opt_timeoutSeconds
- : u2f.EXTENSION_TIMEOUT_SEC;
- var req = u2f.formatSignRequest_(
- appId,
- challenge,
- registeredKeys,
- timeoutSeconds,
- reqId
- );
- port.postMessage(req);
- });
- };
-
- /**
- * Dispatches register requests to available U2F tokens. An array of sign
- * requests identifies already registered tokens.
- * If the JS API version supported by the extension is unknown, it first sends a
- * message to the extension to find out the supported API version and then it sends
- * the register request.
- * @param {string=} appId
- * @param {Array} registerRequests
- * @param {Array} registeredKeys
- * @param {function((u2f.Error|u2f.RegisterResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
- u2f.register = function (
- appId,
- registerRequests,
- registeredKeys,
- callback,
- opt_timeoutSeconds
- ) {
- if (js_api_version === undefined) {
- // Send a message to get the extension to JS API version, then send the actual register request.
- u2f.getApiVersion(function (response) {
- js_api_version =
- response["js_api_version"] === undefined
- ? 0
- : response["js_api_version"];
- console.log("Extension JS API Version: ", js_api_version);
- u2f.sendRegisterRequest(
- appId,
- registerRequests,
- registeredKeys,
- callback,
- opt_timeoutSeconds
- );
- });
- } else {
- // We know the JS API version. Send the actual register request in the supported API version.
- u2f.sendRegisterRequest(
- appId,
- registerRequests,
- registeredKeys,
- callback,
- opt_timeoutSeconds
- );
- }
- };
-
- /**
- * Dispatches register requests to available U2F tokens. An array of sign
- * requests identifies already registered tokens.
- * @param {string=} appId
- * @param {Array} registerRequests
- * @param {Array} registeredKeys
- * @param {function((u2f.Error|u2f.RegisterResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
- u2f.sendRegisterRequest = function (
- appId,
- registerRequests,
- registeredKeys,
- callback,
- opt_timeoutSeconds
- ) {
- u2f.getPortSingleton_(function (port) {
- var reqId = ++u2f.reqCounter_;
- u2f.callbackMap_[reqId] = callback;
- var timeoutSeconds =
- typeof opt_timeoutSeconds !== "undefined"
- ? opt_timeoutSeconds
- : u2f.EXTENSION_TIMEOUT_SEC;
- var req = u2f.formatRegisterRequest_(
- appId,
- registeredKeys,
- registerRequests,
- timeoutSeconds,
- reqId
- );
- port.postMessage(req);
- });
- };
-
- /**
- * Dispatches a message to the extension to find out the supported
- * JS API version.
- * If the user is on a mobile phone and is thus using Google Authenticator instead
- * of the Chrome extension, don't send the request and simply return 0.
- * @param {function((u2f.Error|u2f.GetJsApiVersionResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
- u2f.getApiVersion = function (callback, opt_timeoutSeconds) {
- u2f.getPortSingleton_(function (port) {
- // If we are using Android Google Authenticator or iOS client app,
- // do not fire an intent to ask which JS API version to use.
- if (port.getPortType) {
- var apiVersion;
- switch (port.getPortType()) {
- case "WrappedIosPort_":
- case "WrappedAuthenticatorPort_":
- apiVersion = 1.1;
- break;
-
- default:
- apiVersion = 0;
- break;
- }
- callback({ js_api_version: apiVersion });
- return;
- }
- var reqId = ++u2f.reqCounter_;
- u2f.callbackMap_[reqId] = callback;
- var req = {
- type: u2f.MessageTypes.U2F_GET_API_VERSION_REQUEST,
- timeoutSeconds:
- typeof opt_timeoutSeconds !== "undefined"
- ? opt_timeoutSeconds
- : u2f.EXTENSION_TIMEOUT_SEC,
- requestId: reqId,
- };
- port.postMessage(req);
- });
- };
-})();
diff --git a/views/src/popup/popup.hbs b/views/src/popup/popup.hbs
deleted file mode 100644
index d9ccea1..0000000
--- a/views/src/popup/popup.hbs
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- Popup Auth
-
-
-
-
-
-
-
-
Allow LOADING... to authenticate you?
-
-
-
-
-
-
diff --git a/views/src/popup/popup.js b/views/src/popup/popup.js
deleted file mode 100644
index 0e70e44..0000000
--- a/views/src/popup/popup.js
+++ /dev/null
@@ -1,32 +0,0 @@
-async function getJWT(client_id, hostname) {
- hostname = encodeURIComponent(hostname);
- client_id = encodeURIComponent(client_id);
-
- const res = await fetch(
- `/api/user/jwt?client_id=${client_id}&origin=${hostname}`
- ).then((res) => res.json());
-
- return res;
-}
-
-let acceptPromise;
-
-window.allow = () => acceptPromise();
-window.deny = () => window.close();
-
-function start() {
- let started = false;
- window.addEventListener("message", async (msg) => {
- if (!started) {
- started = true;
- const url = new URL(msg.origin);
- document.getElementById("hostname").innerText = url.hostname;
- await new Promise((yes) => (acceptPromise = yes));
- const res = await getJWT(msg.data.client_id, url.hostname);
- msg.source.postMessage(res, msg.origin);
- window.close();
- }
- });
-}
-
-start();
diff --git a/views/src/popup/popup.scss b/views/src/popup/popup.scss
deleted file mode 100644
index 5811b95..0000000
--- a/views/src/popup/popup.scss
+++ /dev/null
@@ -1,63 +0,0 @@
-@import "@material/button/mdc-button";
-.blue-button {
- background: #4a89dc !important;
-}
-
-.grey-button {
- background: #797979 !important;
-}
-
-hr {
- // display: block;
- // height: 1px;
- border: 0;
- border-top: 1px solid #b8b8b8;
- // margin: 1em 0;
- // padding: 0;
-}
-body {
- font-family: Helvetica;
- background: #eee;
- -webkit-font-smoothing: antialiased;
-}
-
-.title {
- text-align: center;
-}
-
-h1,
-h3 {
- font-weight: 300;
-}
-
-h1 {
- color: #636363;
-}
-
-ul {
- list-style: none;
- padding-left: 0;
-}
-
-.scope_title {
- margin-top: 0;
- margin-bottom: 0;
- padding-left: 5px;
-}
-
-.scope_description {
- margin-top: 0;
- padding-left: 15px;
- font-size: 13px;
- color: #202020;
-}
-
-.card {
- max-width: 480px;
- margin: 4em auto;
- padding: 3em 2em 2em 2em;
- background: #fafafa;
- border: 1px solid #ebebeb;
- box-shadow: rgba(0, 0, 0, 0.14902) 0px 1px 1px 0px,
- rgba(0, 0, 0, 0.09804) 0px 1px 2px 0px;
-}
diff --git a/views_repo b/views_repo
index 4191522..484be5a 160000
--- a/views_repo
+++ b/views_repo
@@ -1 +1 @@
-Subproject commit 4191522b24334f20f7dcda811ca43959b02fef7a
+Subproject commit 484be5a04879ec78c9ab902c92fc166d80dc7f41