diff --git a/Gemfile b/Gemfile index b8d949f..c5eff6a 100644 --- a/Gemfile +++ b/Gemfile @@ -4,4 +4,8 @@ gem 'sinatra' gem 'liquid' gem 'sinatra-flash' gem 'puma' -gem 'sod' \ No newline at end of file +gem 'sod' +gem 'gollum' +gem 'bcrypt' +gem 'sqlite3' +gem 'warden' \ No newline at end of file diff --git a/example/config.ru b/config.ru similarity index 55% rename from example/config.ru rename to config.ru index a041fa3..db8455c 100644 --- a/example/config.ru +++ b/config.ru @@ -1,12 +1,13 @@ -require_relative 'app' +require_relative 'example/app' +require_relative 'example/modules/module' # Require TonTon modules if you want use Rack::Session::Cookie, key: 'rack.session', secret: ENV.fetch('SESSION_SECRET') app = Rack::URLMap.new( - '/' => TonTonWeb::App.new - # Add TonTon modules here + '/' => ExampleApp.new, + '/module' => ExampleModule.new ) run app \ No newline at end of file diff --git a/example/app.rb b/example/app.rb index e5c6f29..11a8d92 100644 --- a/example/app.rb +++ b/example/app.rb @@ -1,18 +1,5 @@ -require 'gollum/app' -require 'sinatra/flash' -require "sqlite3" -require 'tonton_web' +require_relative '../lib/tonton_web' -class TonTonWeb::App < Sinatra::Base - set :host_authorization, { permitted_hosts: ['localhost', 'mytonton.com.br'] } - - set :sessions, true - - get '/' do - redirect "/readme.md" - end - - get '/:name' do - markdown File.read(params['name']), layout_engine: :erb, layout: true - end +class ExampleApp < TonTonWeb::App + set :root, Pathname.new(__FILE__).parent.parent end \ No newline at end of file diff --git a/lib/tonton_web.rb b/lib/tonton_web.rb index 2b4040b..56db1ab 100644 --- a/lib/tonton_web.rb +++ b/lib/tonton_web.rb @@ -1 +1,4 @@ -require_relative 'tonton_web/auth' \ No newline at end of file +require_relative 'tonton_web/auth' +require_relative 'tonton_web/sinatra-auth' +require_relative 'tonton_web/app' +require_relative 'tonton_web/module' \ No newline at end of file diff --git a/lib/tonton_web/app.rb b/lib/tonton_web/app.rb new file mode 100644 index 0000000..30a5d81 --- /dev/null +++ b/lib/tonton_web/app.rb @@ -0,0 +1,109 @@ +require_relative 'auth' +require "warden" +require 'sinatra/flash' + +Warden::Manager.serialize_from_session do |id| + TonTonWeb::App.find_user id: id +end + +Warden::Manager.serialize_into_session do |user| + user.id +end + +Warden::Manager.before_failure do |env,opts| + env['REQUEST_METHOD'] = "POST" + + env['rack.session']['warden.options'] = opts +end + +Warden::Strategies.add(:password) do + def valid? + params['user'] && params['user']['username'] && params['user']['password'] + end + + def authenticate! + user_params = params['user'] + + user = TonTonWeb::App.authenticate user_params['username'], user_params['password'] + + if not user + throw(:warden) + else + success!(user) + end + end +end + +class TonTonWeb::App < Sinatra::Base + @db = SQLite3::Database.new(Dir.getwd + '/database.sqlite') + + register Sinatra::Flash + register TonTonWeb::Auth + + use Warden::Manager do |manager| + manager.default_strategies :password + + manager.failure_app = self + + manager.scope_defaults :default, strategies: [:password], action: 'unauthenticated' + end + + helpers do + def check_authentication + if not env['warden'].authenticated? + flash[:error] = 'You must log in to access this page.' + + redirect '/login' + end + end + + def current_user + env['warden'].user + end + end + + set :host_authorization, { permitted_hosts: ['localhost', 'mytonton.com.br'] } + + get '/' do + redirect "/readme.md" + end + + get '/status' do + puts env['warden'] + check_authentication + "Hello" + end + + post '/unauthenticated' do + session['warden.return_to'] = env['warden.options'][:attempted_path] + + flash[:error] = 'You must log in to access this page.' + + redirect '/login' + end + + get '/login' do + @error = flash[:error] + + erb :login + end + + post '/login' do + env['warden'].authenticate! + + if env['warden'].authenticated? + redirect_path = session.delete('warden.return_to') || '/' + + redirect redirect_path + else + redirect '/login' + end + end + + get '/logout' do + env['warden'].logout + + redirect '/' + end + +end \ No newline at end of file diff --git a/lib/tonton_web/auth.rb b/lib/tonton_web/auth.rb index b48a76b..f34a2aa 100644 --- a/lib/tonton_web/auth.rb +++ b/lib/tonton_web/auth.rb @@ -4,70 +4,63 @@ require 'bcrypt' module TonTonWeb User = Struct.new(:id, :name, :username, :email, :password_digest) +end - class Auth - attr_reader :root +module TonTonWeb::Auth + def create_tables + @db.execute "create table users (id integer primary key, name text, username text, email text, password_digest text);" + end - def initialize root_path - @root = Pathname.new root_path + def create_user **options + name = options.fetch :name + username = options.fetch :username + email = options.fetch :email + password = options.fetch :password - @db = SQLite3::Database.new(@root+ 'database.sqlite') + # 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, hashed_password] + ) + + return # Return user + end + + def delete_user id + @db.execute "delete from users where id = ?;", id + end + + def find_user **options + id = options[:id] + name = options[:name] + username = options[:username] + email = options[:email] + + if not (id or name or username or email) + raise "No options to find user." end - def create_tables - @db.execute "create table users (id integer primary key, name text, username text, email text, password_digest text);" + user = nil + + user_query_template = "select id, name, username, email, password_digest from users where id = ? or name = ? or username = ? or email = ?" + + @db.execute(user_query_template, [id, name, username, email]) do |row| + user = TonTonWeb::User.new(*row) end - def create_user **options - name = options.fetch :name - username = options.fetch :username - email = options.fetch :email - password = options.fetch :password + return user + end - # 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 + def authenticate username, password + user = find_user(username: username) + if BCrypt::Password.new(user.password_digest) == password 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 + else + return false end end end \ No newline at end of file diff --git a/views/login.erb b/views/login.erb new file mode 100644 index 0000000..dfe5c34 --- /dev/null +++ b/views/login.erb @@ -0,0 +1,20 @@ +
+ <%= @error %> +
+<% end %> + + \ No newline at end of file