Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

password hash authentication #19

Merged
merged 1 commit into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions db/test.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
DROP TABLE IF EXISTS users;
CREATE TABLE users(
id INT UNIQUE,
alias VARCHAR(128) NOT NULL UNIQUE,
name VARCHAR(128) NOT NULL,
email VARCHAR(128) UNIQUE,
password VARCHAR(128) NOT NULL,
Expand All @@ -9,6 +10,6 @@ CREATE TABLE users(
);

INSERT INTO users
(id, name, email, password, tier)
(id, alias, name, email, password, tier)
VALUES
(1, "Vivian", "vivian@vivian.com", "vivian123", 5);
(1, "vivian-admin", "vivian", "vivian@vivian.com", "$2a$13$oCCafEIoJJZx/R31iGtOmuGULSIKKnHtytkpAlEYVMWBAuhkWx0Hu", 5);
17 changes: 9 additions & 8 deletions pkg/auth/models/account_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ package models
// simply a prototype for now.
type Account struct {
ID int
Alias string //account username
Email string //account email
Password string //account passphrase
Recovery_key *string //secret key generate for recovery, is deleted once shown
Profile_limit *uint8 //number of profiles the account can maintain, depends on tier
Tier uint8 //account tier level- default: 1
TwoFactorAuth *bool //if 2FA is enabled or not on the account
IP []string //list of users devices IP address
Alias string //account username
Name string //acount holders name
Email string //account email
Password string //account passphrase
Recovery_key *string //secret key generate for recovery, is deleted once shown
Profile_limit *uint8 //number of profiles the account can maintain, depends on tier
Tier uint8 //account tier level- default: 1
TwoFactorAuth *bool //if 2FA is enabled or not on the account
IP *[]string //list of users devices IP address

//optional fields
Secondary_email *string //secondary email for verification & other purposes
Expand Down
5 changes: 2 additions & 3 deletions pkg/server/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func FetchDatabaseData(ctx context.Context) ([]models.Account, error) {
// Loop through rows, using Scan to assign column data to struct fields.
for rows.Next() {
var acc models.Account
if err := rows.Scan(&acc.ID, &acc.Alias, &acc.Email, &acc.Password, &acc.Tier); err != nil {
if err := rows.Scan(&acc.ID, &acc.Alias, &acc.Name, &acc.Email, &acc.Password, &acc.Tier); err != nil {
return accounts, err
}
accounts = append(accounts, acc)
Expand All @@ -85,13 +85,12 @@ func FetchAccount(ctx context.Context, email string) (models.Account, error) {
var acc models.Account
// Loop through rows, using Scan to assign column data to struct fields.
for rows.Next() {
if err := rows.Scan(&acc.ID, &acc.Alias, &acc.Email, &acc.Password, &acc.Tier); err != nil {
if err := rows.Scan(&acc.ID, &acc.Alias, &acc.Name, &acc.Email, &acc.Password, &acc.Tier); err != nil {
return acc, err
}
}
if err = rows.Err(); err != nil {
return acc, err
}
return acc, nil

}
9 changes: 4 additions & 5 deletions pkg/server/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,22 @@ func (l *login) Login(ctx context.Context, email string, password string) (bool,
return false, nil
}

//TODO: implement password sanitization
//TODO: implement password sanitization (follows password requirement rules)
//if !utils.SanitizePasswordCheck(password) {
// log.Error("vivian: ERROR! invalid password")
// return false, nil
//}

fetchedAccount, err := FetchAccount(ctx, email)
if err != nil {
log.Error("vivian: ERROR! failure fetching account", "err", err)
log.Error("vivian: ERROR! failure fetching account, user does not exist", "err", err)
}

if email == fetchedAccount.Email && password == fetchedAccount.Password {
if email == fetchedAccount.Email && utils.VerfiyHashPassword(fetchedAccount.Password, password) {
log.Debug("vivian: SUCCESS! fetched account: ", "alias", fetchedAccount.Alias)
return true, nil
} else {
log.Debug("vivian: ERROR! user does not exist")
log.Debug("vivian: ERROR! invalid credentials")
return false, nil
}

}
156 changes: 78 additions & 78 deletions pkg/web/webui/apps-adduser/add.js
Original file line number Diff line number Diff line change
@@ -1,102 +1,102 @@
function strip(s) {
return s.replace(/\s+/g, '');
}
return s.replace(/\s+/g, '');
}

async function add(endpoint, query, aborter) {
const response = await fetch(`/${endpoint}?q=${query}`, {signal: aborter});
const text = await response.text();
if (response.ok) {
return text;
} else {
throw new Error(text);
}
async function add(endpoint, query, aborter) {
const response = await fetch(`/${endpoint}?q=${query}`, {signal: aborter});
const text = await response.text();
if (response.ok) {
return text;
} else {
throw new Error(text);
}
}

function main() {
const host = document.getElementById('host');
host.innerText = window.location.hostname;
function main() {
const host = document.getElementById('host');
host.innerText = window.location.hostname;

const query = document.getElementById('query');
const addButton = document.getElementById('add');
const loader = document.getElementById('test');
const timer = document.getElementById('time');
const inputs = document.querySelectorAll('input');
const query = document.getElementById('query');
const addButton = document.getElementById('add');
const loader = document.getElementById('test');
const timer = document.getElementById('time');
const inputs = document.querySelectorAll('input');

inputs.forEach(input => {
input.setAttribute('autocomplete', 'off')
input.setAttribute('autocorrect', 'off')
input.setAttribute('autocapitalize', 'off')
input.setAttribute('spellcheck', false)
})
inputs.forEach(input => {
input.setAttribute('autocomplete', 'off')
input.setAttribute('autocorrect', 'off')
input.setAttribute('autocapitalize', 'off')
input.setAttribute('spellcheck', false)
})

addButton.disabled = true;
addButton.disabled = true;

let controller;
let pending = 0;
let controller;
let pending = 0;

const add_user = () => {
if(controller != undefined) {
controller.abort();
}
controller = new AbortController();
const add_user = () => {
if(controller != undefined) {
controller.abort();
}
controller = new AbortController();

for (const endpoint of ['add']) {
for (const endpoint of ['add']) {
if (pending == 0) {
loader.hidden = false;
}
pending++;
var start_time = performance.now();
add(endpoint, query.value, controller.signal).then((x) => {
const results = JSON.parse(strip(x));
if (results == null || results.length == 0) {
loader.innerText = "...";
timer.innerText = "...";
} else {
loader.innerText = x.replace(/"/g, "");
}
}).finally(() => {
pending--;
if (pending == 0) {
loader.hidden = false;
}
pending++;
var start_time = performance.now();
add(endpoint, query.value, controller.signal).then((x) => {
const results = JSON.parse(strip(x));
if (results == null || results.length == 0) {
loader.innerText = "...";
timer.innerText = "...";
} else {
loader.innerText = x.replace(/"/g, "");
}
}).finally(() => {
pending--;
if (pending == 0) {
}
});
timer.innerText = (performance.now() - start_time) + "ms";
}
});
timer.innerText = (performance.now() - start_time) + "ms";
}
}

//optimize these last two elements later, remove need to repeat
const echoApp = document.getElementById('echoApp');
const echoApp = document.getElementById('echoApp');
//const addApp = document.getElementById('addApp');
const echoapp = () => {
window.location.assign("../apps-echo/index.html");
}
const echoapp = () => {
window.location.assign("../apps-echo/index.html");
}
//const addapp = () => {
// window.location.assign("index.html");
//}
echoApp.addEventListener('click', echoapp);
echoApp.addEventListener('click', echoapp);

const fetchApp = document.getElementById('fetchApp');
const fetchapp = () => {
window.location.assign("../apps-fetch/index.html");
}
fetchApp.addEventListener('click', fetchapp);
const fetchApp = document.getElementById('fetchApp');
const fetchapp = () => {
window.location.assign("../apps-fetch/index.html");
}
fetchApp.addEventListener('click', fetchapp);

//addApp.addEventListener('click', addapp);
query.addEventListener('keypress', (e) => {
if (e.key == 'Enter' && strip(query.value) != "") {
add_user();
}
});
query.addEventListener('keypress', (e) => {
if (e.key == 'Enter' && strip(query.value) != "") {
add_user();
}
});

addButton.addEventListener('click', add_user);
query.addEventListener('input', (e) => {
if (strip(query.value) == "") {
addButton.disabled = true;
loader.innerText = "...";
timer.innerText = "...";
} else {
addButton.disabled = false;
}
});
}
addButton.addEventListener('click', add_user);
query.addEventListener('input', (e) => {
if (strip(query.value) == "") {
addButton.disabled = true;
loader.innerText = "...";
timer.innerText = "...";
} else {
addButton.disabled = false;
}
});
}

document.addEventListener('DOMContentLoaded', main);
document.addEventListener('DOMContentLoaded', main);
Loading