diff --git a/Gemfile b/Gemfile index 059924a..1eaac2c 100644 --- a/Gemfile +++ b/Gemfile @@ -2,4 +2,5 @@ source "https://rubygems.org" gem 'sinatra' gem 'sinatra-flash' -gem 'puma' \ No newline at end of file +gem 'puma' +gem 'sod' \ No newline at end of file diff --git a/bin/tauth.rb b/bin/tauth.rb new file mode 100755 index 0000000..c761e03 --- /dev/null +++ b/bin/tauth.rb @@ -0,0 +1,88 @@ +#! /usr/bin/ruby + +require 'sod' + +require_relative '../lib/tonton_web/auth' +require 'io/console' + +class CreateTable < Sod::Action + on "--create-table" + + def call(*) + context.tauth.create_tables + end +end + +class CreateUser < Sod::Command + handle "create-user" + + class Username < Sod::Action + on "--username", argument: "USERNAME" + + def call(username) = context.input[:username] = username + end + + class Name < Sod::Action + on "--name", argument: "NAME" + + def call(name) = context.input[:name] = name + end + + class Email < Sod::Action + on "--email", argument: "EMAIL" + + def call(email) = context.input[:email] = email + end + + on Username + on Name + on Email + + def call + context.input[:password] = IO::console.getpass("User password: ") + + context.tauth.create_user(**context.input) + end +end + +class DeleteUser < Sod::Action + on "--delete-user", argument: "USER_ID" + + def call(user_id) + context.tauth.delete_user user_id + end +end + +class Info < Sod::Command + handle "info" + + description "Information about user." + + class Username < Sod::Action + on "--username", argument: "TEXT" + + def call text + puts context.tauth.find_user(username: text) + end + end + + on Username +end + +tauth = TonTonWeb::Auth.new Dir.getwd + +context = Sod::Context[tauth: tauth, input: {}] + +cli = Sod.new(banner: "Tauth 0.0.0: TonTon Auth") do + on(CreateTable, context:) + + on(CreateUser, context:) + + on(DeleteUser, context:) + + on(Info, context:) + + on Sod::Prefabs::Actions::Help, self +end + +cli.call \ No newline at end of file diff --git a/lib/tonton_web/auth.rb b/lib/tonton_web/auth.rb new file mode 100644 index 0000000..b48a76b --- /dev/null +++ b/lib/tonton_web/auth.rb @@ -0,0 +1,73 @@ +require 'pathname' +require 'sqlite3' +require 'bcrypt' + +module TonTonWeb + User = Struct.new(:id, :name, :username, :email, :password_digest) + + class Auth + attr_reader :root + + def initialize root_path + @root = Pathname.new root_path + + @db = SQLite3::Database.new(@root+ 'database.sqlite') + end + + def create_tables + @db.execute "create table users (id integer primary key, name text, username text, email text, password_digest text);" + end + + def create_user **options + name = options.fetch :name + username = options.fetch :username + email = options.fetch :email + password = options.fetch :password + + # Assert user doesn't exists + + hashed_password = BCrypt::Password.create(password) + + @db.execute( + "insert into users (name, username, email, password_digest) values (?,?,?,?);", + [name, username, email, password] + ) + + return # Return user + end + + def delete_user id + @db.execute "delete from users where id = ?;", id + end + + def find_user **options + name = options[:name] + username = options[:username] + email = options[:email] + + if not (name or username or email) + raise "No options to find user." + end + + user = nil + + user_query_template = "select id, name, username, email, password_digest from users where name = ? or username = ? or email = ?" + + @db.execute(user_query_template, [name, username, email]) do |row| + user = TonTonWeb::User.new(*row) + end + + return user + end + + def authenticate username, password + user = find_user(username: username) + + if BCrypt::Password.new(user.password_digest) == password + return user + else + return false + end + end + end +end \ No newline at end of file