|
|
|
@@ -0,0 +1,303 @@ |
|
|
|
import std.stdio; |
|
|
|
|
|
|
|
//import passwd; |
|
|
|
//import passwd.bcrypt; |
|
|
|
import std.file; |
|
|
|
import std.conv; |
|
|
|
import std.process; |
|
|
|
import arsd.sqlite; |
|
|
|
import std.uuid; |
|
|
|
|
|
|
|
import std.file : isFile, isDir; |
|
|
|
|
|
|
|
class Accounts{ |
|
|
|
private string salt; |
|
|
|
private Database db; |
|
|
|
|
|
|
|
this(string dbName, string salt) { |
|
|
|
this.salt = salt; |
|
|
|
this.db = new Sqlite(dbName); |
|
|
|
} |
|
|
|
string get_salt(){ |
|
|
|
return this.salt; |
|
|
|
} |
|
|
|
void provisiondb(){ |
|
|
|
// The status should determine if a user is suspended, or banned, or in good standing. |
|
|
|
this.db.query("CREATE TABLE IF NOT EXISTS users (username text, password text, alias text, email text, status integer)"); |
|
|
|
this.db.query("CREATE TABLE IF NOT EXISTS sessions (username text, session text)"); |
|
|
|
this.db.query("CREATE TABLE IF NOT EXISTS roles (role text)"); |
|
|
|
this.db.query("CREATE TABLE IF NOT EXISTS userstoroles (userid integer, roleid integer)"); |
|
|
|
// The folowing is expected to hold both directions of friendships. |
|
|
|
// One way relation is contact request, two way is friendship. |
|
|
|
// status determines blocked or not. |
|
|
|
this.db.query("CREATE TABLE IF NOT EXISTS contacts (user integer, contact integer, status integer)"); |
|
|
|
|
|
|
|
//this.db.query("INSERT INTO users values (?, ?, ?)", "user1", "hello", "user1"); |
|
|
|
|
|
|
|
//foreach(line; db.query("SELECT * FROM tablename;")) { |
|
|
|
//writefln("%s %s", line[0], line[1]); |
|
|
|
//} |
|
|
|
} |
|
|
|
bool create_user(string username,string password,string email, string useralias = ""){ |
|
|
|
try{ |
|
|
|
string openssl_command = " openssl passwd -6 --salt \"" ~ this.salt ~ "\" \"" ~ password ~ "\""; |
|
|
|
//writeln(openssl_command); |
|
|
|
auto cont = executeShell(openssl_command); |
|
|
|
if(cont.status != 0) { |
|
|
|
writeln("failed to run openssl command"); |
|
|
|
//return "Failed"; |
|
|
|
return false; |
|
|
|
} else { |
|
|
|
writeln("Salted password: " ~ cont.output); |
|
|
|
//auto file = File("users/"~ username, "w"); |
|
|
|
//file.rawWrite(cont.output); |
|
|
|
//file.close(); |
|
|
|
// We don't need an ID column, we can use rowid, built in. |
|
|
|
this.db.query("INSERT INTO users values (?, ?, ?, ?)", username, cont.output, email, useralias); |
|
|
|
return true; |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
bool delete_user(string username){ |
|
|
|
try{ |
|
|
|
// Delete users to role relation. |
|
|
|
this.db.query("DELETE from userstoroles where userid = (select rowid from users where username = ?)", username); |
|
|
|
this.db.query("DELETE from users where username = ?", username); |
|
|
|
|
|
|
|
return true; |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
string get_user(string session, string role = ""){ |
|
|
|
string username; |
|
|
|
foreach(line; this.db.query("SELECT username FROM sessions where session = ?", session)) { |
|
|
|
//writefln("get_user:: %s", line["username"]); |
|
|
|
username = line["username"]; |
|
|
|
} |
|
|
|
return username; |
|
|
|
} |
|
|
|
bool assume_user(string username){ |
|
|
|
//TODO: This should allow an admin to assume the account of another user. |
|
|
|
try { |
|
|
|
return true; |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
string create_session(string username){ |
|
|
|
try { |
|
|
|
delete_session(username); |
|
|
|
auto namespace = sha1UUID("Accounts"); |
|
|
|
auto sessionid = sha1UUID(username, namespace); |
|
|
|
this.db.query("INSERT INTO sessions values (?, ?)", username, sessionid); |
|
|
|
return sessionid.toString(); |
|
|
|
} catch (Exception e) { |
|
|
|
writeln("failed to create session: " ~e.toString()); |
|
|
|
return ""; |
|
|
|
} |
|
|
|
} |
|
|
|
bool delete_session(string username){ |
|
|
|
try{ |
|
|
|
this.db.query("DELETE from sessions where username = ?", username); |
|
|
|
return true; |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
string login(string username,string password){ |
|
|
|
string session = ""; |
|
|
|
if(check_password(username,password)){ |
|
|
|
session = this.create_session(username); |
|
|
|
return session; |
|
|
|
} |
|
|
|
return session; |
|
|
|
} |
|
|
|
bool logout(string sessionid){ |
|
|
|
try{ |
|
|
|
this.db.query("DELETE FROM sessions where session = ?", sessionid); |
|
|
|
return true; |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
bool authorized_session(string session, string role = ""){ |
|
|
|
//TODO: Rewrite this to be a single query, instead of calling a function?? |
|
|
|
try{ |
|
|
|
string username = get_user(session,role); |
|
|
|
return authorized(username,role); |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
bool authorized(string username, string role = ""){ |
|
|
|
auto rows = db.query("SELECT count(*) FROM userstoroles LEFT JOIN users ON users.rowid = userstoroles.userid LEFT JOIN roles ON roles.rowid = userstoroles.roleid where users.username = ? and roles.role = ?", username, role); |
|
|
|
if(rows.length ==1){ |
|
|
|
return true; |
|
|
|
} else{ |
|
|
|
return false; |
|
|
|
} |
|
|
|
/*foreach(line;rows ) { |
|
|
|
writefln("%s %s", line["password"]); |
|
|
|
stored = line["password"]; |
|
|
|
}*/ |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool check_password(string username,string password){ |
|
|
|
try{ |
|
|
|
string stored; |
|
|
|
foreach(line; db.query("SELECT password FROM users where username = ?", username)) { |
|
|
|
writefln("Password from DB: %s", line["password"]); |
|
|
|
stored = line["password"]; |
|
|
|
} |
|
|
|
string openssl_command = " openssl passwd -6 --salt \"" ~ this.salt ~ "\" \"" ~ password ~ "\""; |
|
|
|
//writeln(openssl_command); |
|
|
|
auto cont = executeShell(openssl_command); |
|
|
|
if(cont.status != 0) { |
|
|
|
writeln("failed to run openssl command"); |
|
|
|
//return "Failed"; |
|
|
|
return false; |
|
|
|
} else { |
|
|
|
writeln("entered password: " ~cont.output); |
|
|
|
if(cont.output == stored){ |
|
|
|
return true; |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
bool create_role(string role){ |
|
|
|
try{ |
|
|
|
this.db.query("INSERT INTO roles values (?)", role); |
|
|
|
return true; |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
bool remove_role(string role){ |
|
|
|
try{ |
|
|
|
this.db.query("DELETE FROM roles where role = ?", role); |
|
|
|
return true; |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
bool assign_role(string username, string role){ |
|
|
|
try{ |
|
|
|
this.db.query("insert into userstoroles values ((select rowid from users where username = ?), (select rowid from roles where role = ?) )", username, role); |
|
|
|
return true; |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
string[] get_roles(string username){ |
|
|
|
string[] roles; |
|
|
|
foreach(line; db.query("SELECT rowid,role FROM roles")) { |
|
|
|
roles ~= line["role"]; |
|
|
|
writefln("%s %s", line["rowid"], line["role"]); |
|
|
|
} |
|
|
|
return roles; |
|
|
|
} |
|
|
|
|
|
|
|
/*bool request_contact(string username, string contact){ |
|
|
|
//TODO: |
|
|
|
try{ |
|
|
|
this.db.query("INSERT into contacts ((select rowid from users where username = ?), (select rowid from users where username = ?), 1)", username, contact); |
|
|
|
return true; |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
bool remove_contact(string username, string contact){ |
|
|
|
//TODO: |
|
|
|
try{ |
|
|
|
this.db.query(" role = ?", role); |
|
|
|
return true; |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bool block_contact(string username, string contact){ |
|
|
|
//TODO: |
|
|
|
try{ |
|
|
|
this.db.query(" role = ?", role); |
|
|
|
return true; |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
bool unblock_contact(string username, string contact){ |
|
|
|
//TODO: |
|
|
|
try{ |
|
|
|
this.db.query(" role = ?", role); |
|
|
|
return true; |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
string[] get_pending_contacts(string username, string contact){ |
|
|
|
//TODO: |
|
|
|
string[] roles; |
|
|
|
foreach(line; db.query("SELECT rowid,role FROM roles")) { |
|
|
|
roles ~= line["role"]; |
|
|
|
writefln("%s %s", line["rowid"], line["role"]); |
|
|
|
} |
|
|
|
return roles; |
|
|
|
} |
|
|
|
// This one shouldn't be needed. |
|
|
|
bool assign_contact(string username, string contact){ |
|
|
|
//TODO: |
|
|
|
try{ |
|
|
|
this.db.query(" role = ?", role); |
|
|
|
return true; |
|
|
|
} catch (Exception e) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
string[] get_contacts(){ |
|
|
|
//TODO: Fill this out, so we can get our contacts list.. |
|
|
|
string[] roles; |
|
|
|
foreach(line; db.query("SELECT rowid,role FROM roles")) { |
|
|
|
roles ~= line["role"]; |
|
|
|
writefln("%s %s", line["rowid"], line["role"]); |
|
|
|
} |
|
|
|
return roles; |
|
|
|
}*/ |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
* NOTE: to use this, just change the main() to tests() so it doesn't run automatically. |
|
|
|
*/ |
|
|
|
|
|
|
|
void main() { |
|
|
|
writeln("Starting account tests."); |
|
|
|
auto accounts = new Accounts("accounts.db", "SALTaosidhfaosihdfSALT"); |
|
|
|
string testuser = "testuser"; |
|
|
|
string testpass = "testpass"; |
|
|
|
string testemail = "testemail"; |
|
|
|
string testalias = "testalias"; |
|
|
|
string testrole = "testrole"; |
|
|
|
accounts.provisiondb(); |
|
|
|
accounts.delete_user(testuser); |
|
|
|
accounts.create_user(testuser,testpass,testemail,testalias); |
|
|
|
//string sessionid = accounts.create_session(testuser); |
|
|
|
string sessionid = accounts.login(testuser,testpass); |
|
|
|
string username = accounts.get_user(sessionid); |
|
|
|
writeln(username); |
|
|
|
assert(username == testuser); |
|
|
|
assert(accounts.remove_role(testrole) == true); |
|
|
|
assert(accounts.create_role(testrole) == true); |
|
|
|
writeln(accounts.get_roles(testuser)); |
|
|
|
assert(accounts.authorized(testuser,testrole) == true); |
|
|
|
assert(accounts.authorized_session(sessionid,testrole) == true); |
|
|
|
assert(accounts.authorized_session(sessionid,"madeuprole") == true); |
|
|
|
//writeln(sessionid); |
|
|
|
assert(accounts.logout(sessionid) == true); |
|
|
|
} |
|
|
|
|