Browse Source

Initial commit

master
admin 1 month ago
commit
fcf5dd4889
2 changed files with 307 additions and 0 deletions
  1. +4
    -0
      README.d
  2. +303
    -0
      accounts.d

+ 4
- 0
README.d View File

@@ -0,0 +1,4 @@
This is an accounts/user library.
Backed in sqlite via arsd.sqlite



+ 303
- 0
accounts.d View File

@@ -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);
}


Loading…
Cancel
Save