gem "sinatra" gem "oauth" gem "rack-flash3" require "sinatra" require "erb" require "fileutils" require "rack/flash" require "oauth" require "json" require "uri" require "securerandom" include ERB::Util DATADIR = ENV["DATADIR"] || File.join(__dir__, "data") CONSUMER_KEY = ENV["CONSUMER_KEY"] CONSUMER_SECRET = ENV["CONSUMER_SECRET"] SESSION_SECRET = SecureRandom.random_bytes(32) set :public_folder, DATADIR use Rack::Session::Cookie, expire_after: (86400 * 7), secret: SESSION_SECRET use Rack::Flash def user_id id = session[:user_id] raise "not logged in" unless id raise "broken format user id" if /\A\d+\z/ !~ id id end def logged_in? !!session[:user_id] end def consumer $consumer ||= OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET, site: "https://api.twitter.com", authorize_path: "/oauth/authenticate") end def authenticate! redirect "/" unless session[:user_id] end get "/" do if logged_in? ids = Dir.glob(File.join(DATADIR, session[:user_id], "*")).map { |path| File.basename(path) } erb :index, locals: { ids: ids, user_id: session[:user_id] } else uri = URI.parse(request.url).merge!("./callback") req = consumer.get_request_token(oauth_callback: uri.to_s) session[:req] = JSON.generate(token: req.token, secret: req.secret) redirect req.authorize_url end end get "/callback" do if session[:req] json = JSON.parse(session.delete(:req), symbolize_names: true) if params[:oauth_token] == json[:token] req = OAuth::RequestToken.new(consumer, json[:token], json[:secret]) acc = req.get_access_token(oauth_verifier: params[:oauth_verifier]) session[:user_id] = acc.params[:user_id] session[:acc] = JSON.generate(token: acc.token, secret: acc.secret) FileUtils.mkdir_p(File.join(DATADIR, user_id)) end end redirect "/" end post "/update" do authenticate! return 400 unless /\A\d+-[a-f0-9]{40}\z/ =~ params[:id].to_s path = File.join(DATADIR, user_id, params[:id]) return 404 unless File.exist?(path) encoded = [File.read(path)].pack("m0") json = JSON.parse(session.fetch(:acc), symbolize_names: true) acc = OAuth::AccessToken.new(consumer, json[:token], json[:secret]) acc.post("/1.1/account/update_profile_image.json", image: encoded) flash[:notice] = "Successfully updated" redirect "/" end post "/upload" do authenticate! tempfile = params.dig(:file, :tempfile) return 400 unless tempfile return 400 if tempfile.size > 5 * 1024 * 1024 digest = Digest::SHA1.file(tempfile).hexdigest id = Time.now.to_i.to_s + "-" + digest File.write(File.join(DATADIR, user_id, id), tempfile.read) flash[:notice] = "Successfully uploaded" redirect "/" end __END__ @@ index icon.rhe.jp <% if flash[:notice] %>
<%=h flash[:notice] %>
<% end %>
<% ids.each do |id| %> <%=h id %> <% end %>