Initial commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
This is an accounts/user library.
|
||||
Backed in sqlite via arsd.sqlite
|
||||
|
||||
|
||||
+303
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user