···66require 'openssl'
7788class Authenticator
99+ class InvalidTokenError < StandardError
1010+ end
1111+912 def initialize(hostname:)
1013 @@pkey_cache ||= {}
1114 @hostname = hostname
···1518 return nil unless auth_header.start_with?('Bearer ')
16191720 token = auth_header.gsub(/\ABearer /, '')
1818- data = JSON.parse(Base64.decode64(token.split('.')[1]))
2121+ parts = token.split('.')
2222+ raise InvalidTokenError, "Invalid JWT token" if parts.length != 3
2323+2424+ begin
2525+ decoded_data = Base64.decode64(parts[1])
2626+ data = JSON.parse(decoded_data)
2727+ rescue StandardError => e
2828+ raise InvalidTokenError, "Invalid JWT token"
2929+ end
3030+1931 did = data['iss']
2020- return nil if data['aud'] != "did:web:#{@hostname}" || data['lxm'] != endpoint
3232+ return nil if did.nil? || data['aud'] != "did:web:#{@hostname}" || data['lxm'] != endpoint
21332234 pkey = pkey_for_user(did)
2335
+43-19
app/server.rb
···2323 content_type :json
2424 [status, JSON.generate({ error: name, message: message })]
2525 end
2626+2727+ def get_user_did
2828+ if settings.development?
2929+ if did = params[:user]
3030+ return did
3131+ else
3232+ halt json_error('AuthMissing', 'Missing "user" parameter', status: 401)
3333+ end
3434+ else
3535+ auth_header = env['HTTP_AUTHORIZATION']
3636+ if auth_header.to_s.strip.empty?
3737+ halt json_error('AuthMissing', 'Missing authentication header', status: 401)
3838+ end
3939+4040+ begin
4141+ did = @authenticator.decode_user_from_jwt(auth_header, 'blue.feeds.lycan.searchPosts')
4242+ rescue StandardError => e
4343+ halt json_error('InvalidToken', e.message, status: 401)
4444+ end
4545+4646+ if did
4747+ return did
4848+ else
4949+ halt json_error('InvalidToken', "Invalid JWT token", status: 401)
5050+ end
5151+ end
5252+ end
5353+5454+ def load_user
5555+ did = get_user_did
5656+5757+ if user = User.find_by(did: did)
5858+ return user
5959+ else
6060+ halt json_error('AccountNotFound', 'Account not found', status: 401)
6161+ end
6262+ end
2663 end
27642865 before do
···3269 get '/xrpc/blue.feeds.lycan.searchPosts' do
3370 headers['access-control-allow-origin'] = '*'
34713535- if settings.development?
3636- user = User.find_by(did: params[:user])
3737- return json_error('UserNotFound', 'Missing "user" parameter') if user.nil?
3838- else
3939- begin
4040- auth_header = env['HTTP_AUTHORIZATION']
4141- did = @authenticator.decode_user_from_jwt(auth_header, 'blue.feeds.lycan.searchPosts')
4242- rescue StandardError => e
4343- p e
4444- end
4545-4646- user = did && User.find_by(did: did)
4747- return json_error('UserNotFound', 'Missing authentication header') if user.nil?
4848- end
7272+ @user = load_user
49735074 if params[:query].to_s.strip.empty?
5175 return json_error('MissingParameter', 'Missing "query" parameter')
···5882 query = QueryParser.new(params[:query])
59836084 collection = case params[:collection]
6161- when 'likes' then user.likes
6262- when 'pins' then user.pins
6363- when 'quotes' then user.quotes
6464- when 'reposts' then user.reposts
8585+ when 'likes' then @user.likes
8686+ when 'pins' then @user.pins
8787+ when 'quotes' then @user.quotes
8888+ when 'reposts' then @user.reposts
6589 else return json_error('InvalidParameter', 'Invalid search collection')
6690 end
6791···8010481105 post_uris = case params[:collection]
82106 when 'quotes'
8383- items.map { |x| "at://#{user.did}/app.bsky.feed.post/#{x.rkey}" }
107107+ items.map { |x| "at://#{@user.did}/app.bsky.feed.post/#{x.rkey}" }
84108 else
85109 items.map(&:post).map(&:at_uri)
86110 end