Skip to content
Snippets Groups Projects
Commit 1dad72bf authored by Eugen Rochko's avatar Eugen Rochko
Browse files

Fixes and general progress

parent 709c6685
No related branches found
No related tags found
No related merge requests found
......@@ -7,7 +7,7 @@ class XrdController < ApplicationController
def webfinger
@account = Account.find_by!(username: username_from_resource, domain: nil)
@canonical_account_uri = "acct:#{@account.username}#{LOCAL_DOMAIN}"
@canonical_account_uri = "acct:#{@account.username}@#{LOCAL_DOMAIN}"
@magic_key = pem_to_magic_key(@account.keypair.public_key)
end
......
module ApplicationHelper
include GrapeRouteHelpers::NamedRouteMatcher
include RoutingHelper
def unique_tag(date, id, type)
"tag:#{LOCAL_DOMAIN},#{date.strftime('%Y-%m-%d')}:objectId=#{id}:objectType=#{type}"
end
def subscription_url(account)
add_base_url_prefix subscription_path(id: account.id, format: '')
add_base_url_prefix subscriptions_path(id: account.id, format: '')
end
def salmon_url(account)
......@@ -14,6 +14,6 @@ module ApplicationHelper
end
def add_base_url_prefix(suffix)
"#{root_url}api#{suffix}"
File.join(root_url, "api", suffix)
end
end
module RoutingHelper
extend ActiveSupport::Concern
include Rails.application.routes.url_helpers
include GrapeRouteHelpers::NamedRouteMatcher
included do
def default_url_options
ActionMailer::Base.default_url_options
end
end
end
......@@ -29,6 +29,18 @@ class Account < ActiveRecord::Base
self.domain.nil?
end
def acct
local? ? self.username : "#{self.username}@#{self.domain}"
end
def object_type
:person
end
def subscribed?
!(self.secret.blank? || self.verify_token.blank?)
end
def keypair
self.private_key.nil? ? OpenSSL::PKey::RSA.new(self.public_key) : OpenSSL::PKey::RSA.new(self.private_key)
end
......
......@@ -2,6 +2,28 @@ class Follow < ActiveRecord::Base
belongs_to :account
belongs_to :target_account, class_name: 'Account'
validates :account, :target_account, presence: true
def verb
:follow
end
def object_type
:person
end
def target
self.target_account
end
def content
"#{self.account.acct} started following #{self.target_account.acct}"
end
def title
content
end
after_create do
self.account.stream_entries.create!(activity: self)
end
......
class Status < ActiveRecord::Base
belongs_to :account, inverse_of: :statuses
validates :account, presence: true
def verb
:post
end
def object_type
:note
end
def content
self.text
end
def title
content.truncate(80, omission: "...")
end
after_create do
self.account.stream_entries.create!(activity: self)
end
......
......@@ -2,32 +2,29 @@ class StreamEntry < ActiveRecord::Base
belongs_to :account, inverse_of: :stream_entries
belongs_to :activity, polymorphic: true
validates :account, :activity, presence: true
def object_type
case self.activity_type
when 'Status'
:note
when 'Follow'
:person
end
self.activity.object_type
end
def verb
case self.activity_type
when 'Status'
:post
when 'Follow'
:follow
end
self.activity.verb
end
def targeted?
[:follow].include? self.verb
end
def target
case self.activity_type
when 'Follow'
self.activity.target_account
end
self.activity.target
end
def title
self.activity.title
end
def content
self.activity.text if self.activity_type == 'Status'
self.activity.content
end
end
class User < ActiveRecord::Base
belongs_to :account, inverse_of: :user
validates :account, presence: true
end
......@@ -5,10 +5,13 @@ class FollowRemoteAccountService
username, domain = uri.split('@')
account = Account.where(username: username, domain: domain).first
return account unless account.nil?
if account.nil?
account = Account.new(username: username, domain: domain)
elsif account.subscribed?
return account
end
account = Account.new(username: username, domain: domain)
data = Goldfinger.finger("acct:#{uri}")
data = Goldfinger.finger("acct:#{uri}")
account.remote_url = data.link('http://schemas.google.com/g/2010#updates-from').href
account.salmon_url = data.link('salmon').href
......@@ -21,16 +24,20 @@ class FollowRemoteAccountService
feed = get_feed(account.remote_url)
hubs = feed.xpath('//xmlns:link[@rel="hub"]')
return false if hubs.empty? || hubs.first.attribute('href').nil? || feed.at_xpath('/xmlns:author/xmlns:uri').nil?
return nil if hubs.empty? || hubs.first.attribute('href').nil? || feed.at_xpath('/xmlns:feed/xmlns:author/xmlns:uri').nil?
account.uri = feed.at_xpath('/xmlns:author/xmlns:uri').content
account.uri = feed.at_xpath('/xmlns:feed/xmlns:author/xmlns:uri').content
account.hub_url = hubs.first.attribute('href').value
get_profile(feed, account)
account.save!
subscription = account.subscription(subscription_url(account))
subscription.subscribe
return account
rescue Goldfinger::Error, HTTP::Error => e
false
nil
end
private
......@@ -40,6 +47,20 @@ class FollowRemoteAccountService
Nokogiri::XML(response)
end
def get_profile(xml, account)
author = xml.at_xpath('/xmlns:feed/xmlns:author')
if author.at_xpath('./poco:displayName').nil?
account.display_name = account.username
else
account.display_name = author.at_xpath('./poco:displayName').content
end
unless author.at_xpath('./poco:note').nil?
account.note = author.at_xpath('./poco:note').content
end
end
def magic_key_to_pem(magic_key)
_, modulus, exponent = magic_key.split('.')
modulus, exponent = [modulus, exponent].map { |n| Base64.urlsafe_decode64(n).bytes.inject(0) { |num, byte| (num << 8) | byte } }
......
class FollowService
def call(source_account, uri)
target_account = follow_remote_account_service.(uri)
source_account.follow!(target_account)
source_account.follow!(target_account) unless target_account.nil?
end
private
......
......@@ -15,20 +15,29 @@ Nokogiri::XML::Builder.new do |xml|
end
xml.link(rel: 'alternate', type: 'text/html', href: profile_url(name: @account.username))
xml.link(rel: 'hub', href: '')
xml.link(rel: 'hub', href: HUB_URL)
xml.link(rel: 'salmon', href: salmon_url(@account))
xml.link(rel: 'self', type: 'application/atom+xml', href: atom_user_stream_url(id: @account.id))
@account.stream_entries.each do |stream_entry|
xml.entry do
xml.id_ unique_tag(stream_entry.created_at, stream_entry.activity_id, stream_entry.activity_type)
xml.published stream_entry.activity.created_at.iso8601
xml.updated stream_entry.activity.updated_at.iso8601
xml.content({ type: 'html' }, stream_entry.content)
xml.title
xml.title stream_entry.title
xml.content({ type: 'html' }, stream_entry.content)
xml['activity'].send('verb', "http://activitystrea.ms/schema/1.0/#{stream_entry.verb}")
xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{stream_entry.object_type}")
if stream_entry.targeted?
xml['activity'].send('object') do
xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{stream_entry.target.object_type}")
xml.id_ stream_entry.target.uri
end
else
xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{stream_entry.object_type}")
end
end
end
end
......
Nokogiri::XML::Builder.new do |xml|
xml.XRD(xmlns: 'http://docs.oasis-open.org/ns/xri/xrd-1.0') do
xml.Subject @canonical_account_uri
xml.Alias profile_url(name: @account.username)
xml.Link(rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: profile_url(name: @account.username))
xml.Link(rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: atom_user_stream_url(id: @account.id))
xml.Link(rel: 'salmon', href: salmon_url(@account))
xml.Link(rel: 'magic-public-key', href: @magic_key)
......
......@@ -6,6 +6,8 @@ require 'rails/all'
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
Dotenv::Railtie.load
module Mastodon
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
......
......@@ -38,6 +38,4 @@ Rails.application.configure do
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
config.action_mailer.default_url_options = { host: ENV['NGROK_HOST'] }
end
LOCAL_DOMAIN = ENV['LOCAL_DOMAIN'] || 'localhost'
HUB_URL = ENV['HUB_URL'] || 'https://pubsubhubbub.superfeedr.com'
Rails.application.configure do
config.action_mailer.default_url_options = { host: LOCAL_DOMAIN }
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment