require 'bundler/setup' Bundler.require require 'sinatra/reloader' if development? require 'active_support/core_ext' enable :sessions configure do #どの環境でも起動時に1回だけ実行される set :flags => (1..6).to_a.map{|i| [i, 0]}.to_h #どのチームが押したか管理するためのハッシュ end #WebSocketを使うときの設定 set :server, 'thin' set :sockets, [] #logを端末上に標準エラー出力する logger = Logger.new(STDOUT) #管理者用のデータベースの設定 ActiveRecord::Base.establish_connection( adapter: 'sqlite3', database: './db/accounts.db' ) #データベースへの永続接続回避 after do ActiveRecord::Base.connection.close end #ActiveRecordのusersテーブルを扱う class User < ActiveRecord::Base end #参加者の早押しボタンページ get '/' do if session[:team].blank? #チームがsetされていないときに選択画面に遷移する erb :select else pushed=Array.new settings.flags.sort_by{|key,value| value}.each do |key, value| if value==0 next else pushed.push("<li>チーム#{key}</li>") end end @pushed=pushed.join("\n") erb :index end end #WebSocket通信の処理 get '/websocket' do if request.websocket? #WebSocket通信かどうかを確認 request.websocket do |ws| ws.onopen do #最初に開いたときの処理 settings.sockets << ws end ws.onmessage do |btn| #ボタン or resetが押された時の処理 logger.debug(btn) if session[:team].present? && btn=="Stop!" if session[:team]>=1 && session[:team]<=6 && settings.flags[session[:team]]==0 settings.flags[session[:team]] = settings.flags.values.inject(:+) + 1 t_name="チーム#{session[:team]}" logger.debug(settings.flags) settings.sockets.each do |s| s.send(t_name) end end elsif session[:admin].present? && btn=="Delete!" #controllerでresetを押された時の処理 if session[:admin]==8804912 settings.sockets.each do |s| settings.flags=(1..6).to_a.map{|i| [i, 0]}.to_h logger.debug(settings.flags) s.send("Delete!") end end end end ws.onclose do #ブラウザ閉じたりとかしてWebSocket通信が切れた時の処理 settings.sockets.delete(ws) end end end end #チーム決定ボタンを押した時の処理 post '/setteam' do t_num=params[:t_num].to_i if t_num>=1 && t_num<=6 session[:team]=t_num redirect "/" else session.clear erb :error end end #チーム再選択ボタンを押した時の処理 get '/resetteam' do session.clear #チーム番号を保持しているセッションを消す redirect "/" end #プロジェクターや手元に解答順番を映す用の画面 get '/viewer' do pushed=Array.new settings.flags.sort_by{|key,value| value}.each do |key, value| if value==0 next else pushed.push("<li>チーム#{key}</li>") end end @pushed=pushed.join("\n") erb :viewer end #出題者が操作するページ get '/controller' do #admin if session[:admin].blank? erb :login elsif session[:admin]==8804912 pushed=Array.new settings.flags.sort_by{|key,value| value}.each do |key, value| if value==0 next else pushed.push("<li>チーム#{key}</li>") end end @pushed=pushed.join("\n") erb :controller end end #出題者のログイン認証 post '/check' do if params[:user_id] user_id = params[:user_id] session[:user_id] = user_id user=User.find_by(user_id: user_id) salt = [OpenSSL::Random.random_bytes(32)].pack("m").chomp! session[:salt]=salt logger.debug("hogehoge"+salt) logger.debug(user) if user.blank? salt_dummy = [OpenSSL::Random.random_bytes(32)].pack("m").chomp! {nounce: salt_dummy, salt: salt}.to_json else logger.debug("akanwa") {nounce: user.salt, salt: salt}.to_json end elsif params[:password] password = params[:password] user=User.find_by(user_id: session[:user_id]) if user.blank? return end payload = user.password_digest hmac = OpenSSL::HMAC.hexdigest('sha256', session[:salt], payload) logger.debug(hmac) payload2 = hmac logger.debug(params[:salt]) hmac2 = OpenSSL::HMAC.hexdigest('sha256', params[:salt], payload2) logger.debug(hmac2) if password == hmac2 session[:admin]=8804912 return else return end end end