WIP: Add Two Factor Authentication #7
5 changed files with 70 additions and 24 deletions
|
@ -1,7 +1,10 @@
|
|||
package misc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"code.lila.network/adoralaura/go-urlsh/models"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
|
@ -30,6 +33,11 @@ func New400Error() error {
|
|||
return fiber.NewError(fiber.StatusBadRequest, "400 Bad Request")
|
||||
}
|
||||
|
||||
func New400WithMessageError(msg string) error {
|
||||
body, _ := json.Marshal(models.HttpErrorBody{Message: msg})
|
||||
return fiber.NewError(fiber.StatusBadRequest, string(body[:]))
|
||||
}
|
||||
|
||||
func New401Error() error {
|
||||
return fiber.NewError(fiber.StatusUnauthorized, "401 Unauthorized")
|
||||
}
|
||||
|
|
|
@ -21,14 +21,13 @@ func HandleAdminLoginMFAPost(c *fiber.Ctx) error {
|
|||
return misc.New400Error()
|
||||
}
|
||||
|
||||
var token models.TokenRequest
|
||||
token := new(models.TokenRequest)
|
||||
var istotp bool
|
||||
|
||||
if err := c.BodyParser(&token); err != nil {
|
||||
if err := c.BodyParser(token); err != nil {
|
||||
// TODO: Debug logging
|
||||
return misc.New400Error()
|
||||
}
|
||||
|
||||
if len(token.Token) == 6 {
|
||||
istotp = true
|
||||
} else if len(token.Token) == 8 {
|
||||
|
@ -42,7 +41,7 @@ func HandleAdminLoginMFAPost(c *fiber.Ctx) error {
|
|||
if err != nil {
|
||||
log.Println(err)
|
||||
// TODO: Debug logging
|
||||
return misc.New500Error()
|
||||
return misc.New400Error()
|
||||
}
|
||||
|
||||
// check token/scratch validity
|
||||
|
@ -57,11 +56,10 @@ func HandleAdminLoginMFAPost(c *fiber.Ctx) error {
|
|||
err = misc.SetLoginCookie(c, user, constants.LoginCookieExpiryDuration)
|
||||
if err != nil {
|
||||
log.Printf("[HandleAdminLoginPost] Error setting cookie: %q\n", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error")
|
||||
return misc.New500Error()
|
||||
}
|
||||
|
||||
c.Status(fiber.StatusSeeOther)
|
||||
c.Location("/admin/")
|
||||
c.Status(fiber.StatusOK)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
5
models/error.go
Normal file
5
models/error.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
package models
|
||||
|
||||
type HttpErrorBody struct {
|
||||
Message string `json:"message"`
|
||||
}
|
|
@ -7,8 +7,11 @@
|
|||
<title>Multi Factor Authentication - go-urlsh</title>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
<link rel="stylesheet" href="/admin/pico.min.css">
|
||||
<script src="/admin/main.js" defer></script>
|
||||
<style>
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
@ -17,13 +20,16 @@
|
|||
<article class="grid">
|
||||
<div>
|
||||
<hgroup>
|
||||
<h1 style='--color: var(--h1-color); font-weight: var(--font-weight); font-size: var(--font-size); font-family: var(--font-family);'>Multi Factor Authentication</h1>
|
||||
<h1
|
||||
style='--color: var(--h1-color); font-weight: var(--font-weight); font-size: var(--font-size); font-family: var(--font-family);'>
|
||||
Multi Factor Authentication</h1>
|
||||
|
||||
</hgroup>
|
||||
<form method="post" action="/admin/login/multifactor" style="margin-bottom: 0;" autocomplete="off">
|
||||
<form action="javascript:HandleMFALoginTokenPost()" style="margin-bottom: 0;" autocomplete="off">
|
||||
<label for="token">Authentication Code (Format: 123456 or a1b2c3d4 for recovery codes)</label>
|
||||
<input type="text" name="token" id="token" autocomplete="one-time-code">
|
||||
|
||||
<input type="submit" value="Submit" class="contrast">
|
||||
<p id="error-message" class="hidden" style="color: red;">Error Message</p>
|
||||
<input id="submit" type="submit" value="Submit" class="contrast">
|
||||
</form>
|
||||
</div>
|
||||
</article>
|
||||
|
|
53
web/main.js
53
web/main.js
|
@ -1,6 +1,6 @@
|
|||
// Link overview
|
||||
|
||||
async function HandleLinkIndexDelete(id){
|
||||
async function HandleLinkIndexDelete(id) {
|
||||
let response = await fetch("/api/v1/links/" + id, {
|
||||
credentials: "include",
|
||||
mode: "same-origin",
|
||||
|
@ -30,7 +30,7 @@ async function HandleLinkEditSubmit() {
|
|||
await LinkAction("edit")
|
||||
}
|
||||
|
||||
async function LinkAction(action){
|
||||
async function LinkAction(action) {
|
||||
document.getElementById("submit").active = false
|
||||
let slug = document.getElementById("linkname").value
|
||||
let url = document.getElementById("link").value
|
||||
|
@ -38,22 +38,22 @@ async function LinkAction(action){
|
|||
|
||||
let method, endpoint = ""
|
||||
let body;
|
||||
switch(action) {
|
||||
switch (action) {
|
||||
case "add":
|
||||
method = "POST"
|
||||
endpoint = "/api/v1/links/"
|
||||
body = {
|
||||
"id" : slug,
|
||||
"url" : url,
|
||||
"description" : description
|
||||
"id": slug,
|
||||
"url": url,
|
||||
"description": description
|
||||
}
|
||||
break;
|
||||
case "edit":
|
||||
method = "PUT"
|
||||
endpoint = "/api/v1/links/" + slug
|
||||
body = {
|
||||
"url" : url,
|
||||
"description" : description
|
||||
"url": url,
|
||||
"description": description
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -82,8 +82,7 @@ async function LinkAction(action){
|
|||
async function HandleLinkFieldChange() {
|
||||
console.log("HandleChange")
|
||||
let buttonactive = true
|
||||
if (document.getElementById("link").value === "")
|
||||
{
|
||||
if (document.getElementById("link").value === "") {
|
||||
buttonactive = false
|
||||
}
|
||||
document.getElementById("submit").active = buttonactive
|
||||
|
@ -98,7 +97,7 @@ async function HandleApiKeyNewSubmit() {
|
|||
button.setAttribute("aria-busy", "true")
|
||||
|
||||
let body = {
|
||||
"description" : description
|
||||
"description": description
|
||||
}
|
||||
|
||||
let response = await fetch("/api/v1/apikeys", {
|
||||
|
@ -121,12 +120,13 @@ async function HandleMFASetupTokenSubmit() {
|
|||
let token = document.getElementById("token").value
|
||||
|
||||
let body = {
|
||||
"token" : token
|
||||
"token": token
|
||||
}
|
||||
|
||||
let response = await fetch("/admin/account/mfasetup", {
|
||||
credentials: "include",
|
||||
body: JSON.stringify(body),
|
||||
headers: { "Content-Type": "application/json", },
|
||||
mode: "same-origin",
|
||||
method: "POST"
|
||||
});
|
||||
|
@ -145,6 +145,35 @@ async function HandleMFASetupTokenSubmit() {
|
|||
}
|
||||
}
|
||||
|
||||
async function HandleMFALoginTokenPost() {
|
||||
document.getElementById("submit").disabled = true;
|
||||
document.getElementById("token").disabled = true;
|
||||
let token = document.getElementById("token").value
|
||||
let body = {
|
||||
"token": token
|
||||
}
|
||||
|
||||
let response = await fetch("/admin/login/multifactor", {
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json", },
|
||||
body: JSON.stringify(body),
|
||||
mode: "same-origin",
|
||||
method: "POST"
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
document.location = "/admin/"
|
||||
} else {
|
||||
document.getElementById("submit").disabled = false;
|
||||
document.getElementById("token").disabled = false;
|
||||
document.getElementById('error-message').innerHTML = "Two Factor Authentication failed. Please try again."
|
||||
document.getElementById('error-message').setAttribute("class", "")
|
||||
document.getElementById('token').value = ""
|
||||
document.getElementById('token').setAttribute("aria-invalid", "true")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function HandleModalClose(redir) {
|
||||
document.getElementById('dialog-success').close();
|
||||
document.getElementById('dialog-error').close();
|
||||
|
|
Loading…
Reference in a new issue