require 'gollum/app' require 'warden' require 'sinatra/flash' require 'securerandom' require "sqlite3" class TonTon end TonTon::User = Struct.new(:id, :username, :email, :name, :password) Warden::Manager.serialize_into_session do |user| user.id end Warden::Manager.serialize_from_session do |id| TonTon::App.find_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 = TonTon::App.find_user_by_username user_params['username'] if user and user.password == user_params['password'] success!(user) else throw(:warden) end end end class TonTon::App < Precious::App use Warden::Manager do |manager| manager.default_strategies :password manager.failure_app = self manager.scope_defaults :default, strategies: [:password], action: 'unauthenticated' end register Sinatra::Flash set :root, File.dirname(__FILE__) @db = SQLite3::Database.new "database.sqlite" def self.find_user id user = nil @db.execute("select id, username, email, name, password from users where id = ?", id) do |row| user = TonTon::User.new(*row) end return user end def self.find_user_by_username username user = nil @db.execute("select id, username, email, name, password from users where username = ?", username) do |row| user = TonTon::User.new(*row) end return user end helpers do def check_authentication if not env['warden'].authenticated? flash[:error] = 'You must log in to access this page.' redirect '/login' else session['gollum.author'] = { name: current_user.name, email: current_user.email } end end def current_user env['warden'].user end end before do public_patterns = [ '/', '/*', '/login', '/logout', '/unauthenticated', '/gollum/*', '/gollum/history/**', '/gollum/latest_changes', '/gollum/commit/**' ] request_path = Pathname.new(request.path_info) looks_public = false for pattern in public_patterns if request_path.fnmatch(pattern, File::FNM_PATHNAME) looks_public = true end end if not looks_public then check_authentication end 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