Toot toooooooot (Bluesky-Mastodon cross-poster)

switched to oauth flow by authorizing on a website

+15 -7
app/mastodon_account.rb
··· 20 20 File.write(CONFIG_FILE, YAML.dump(@config)) 21 21 end 22 22 23 - def oauth_login(handle, email, password) 23 + def oauth_login(handle) 24 24 instance = handle.split('@').last 25 25 app_response = register_oauth_app(instance, OAUTH_SCOPES) 26 26 27 27 api = MastodonAPI.new(instance) 28 28 29 - json = api.oauth_login_with_password( 30 - app_response.client_id, 31 - app_response.client_secret, 32 - email, password, OAUTH_SCOPES 33 - ) 29 + login_url = api.generate_oauth_login_url(app_response.client_id, OAUTH_SCOPES) 30 + 31 + puts "Open this URL in your web browser and authorize the app:" 32 + puts 33 + puts login_url 34 + puts 35 + puts "Then, enter the received code here:" 36 + puts 37 + 38 + print ">> " 39 + code = STDIN.gets.chomp 40 + 41 + json = api.complete_oauth_login(app_response.client_id, app_response.client_secret, code) 34 42 35 43 api.access_token = json['access_token'] 36 44 info = api.account_info ··· 43 51 44 52 def register_oauth_app(instance, scopes) 45 53 client = Mastodon::REST::Client.new(base_url: "https://#{instance}") 46 - client.create_app(APP_NAME, 'urn:ietf:wg:oauth:2.0:oob', scopes) 54 + client.create_app(APP_NAME, MastodonAPI::CODE_REDIRECT_URI, scopes) 47 55 end 48 56 49 57 def post_status(text, media_ids = nil, parent_id = nil)
+19 -5
app/mastodon_api.rb
··· 3 3 require 'uri' 4 4 5 5 class MastodonAPI 6 + CODE_REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob' 7 + 6 8 class UnauthenticatedError < StandardError 7 9 end 8 10 ··· 32 34 @access_token = access_token 33 35 end 34 36 35 - def oauth_login_with_password(client_id, client_secret, email, password, scopes) 37 + def generate_oauth_login_url(client_id, scopes) 38 + login_url = URI("https://#{@host}/oauth/authorize") 39 + 40 + login_url.query = URI.encode_www_form( 41 + client_id: client_id, 42 + redirect_uri: CODE_REDIRECT_URI, 43 + response_type: 'code', 44 + scope: scopes 45 + ) 46 + 47 + login_url 48 + end 49 + 50 + def complete_oauth_login(client_id, client_secret, code) 36 51 params = { 37 52 client_id: client_id, 38 53 client_secret: client_secret, 39 - grant_type: 'password', 40 - scope: scopes, 41 - username: email, 42 - password: password 54 + redirect_uri: CODE_REDIRECT_URI, 55 + grant_type: 'authorization_code', 56 + code: code 43 57 } 44 58 45 59 post_json("https://#{@host}/oauth/token", params)
+3 -10
app/tootify.rb
··· 26 26 end 27 27 end 28 28 29 - def login_bluesky(handle) 29 + def login_to_bluesky(handle) 30 30 handle = handle.gsub(/^@/, '') 31 31 32 32 print "App password: " ··· 36 36 @bluesky.login_with_password(handle, password) 37 37 end 38 38 39 - def login_mastodon(handle) 40 - print "Email: " 41 - email = STDIN.gets.chomp 42 - 43 - print "Password: " 44 - password = STDIN.noecho(&:gets).chomp 45 - puts 46 - 47 - @mastodon.oauth_login(handle, email, password) 39 + def login_to_mastodon(handle) 40 + @mastodon.oauth_login(handle) 48 41 end 49 42 50 43 def sync
+2 -2
tootify
··· 36 36 app = Tootify.new 37 37 38 38 if name =~ /\A[^@]+@[^@]+\z/ 39 - app.login_mastodon(name) 39 + app.login_to_mastodon(name) 40 40 elsif name =~ /\A@[^@]+\z/ 41 - app.login_bluesky(name) 41 + app.login_to_bluesky(name) 42 42 elsif name.nil? 43 43 print_help 44 44 else