├── .codeclimate.yml
├── .editorconfig
├── .github
└── workflows
│ ├── ci.yml
│ └── lint.yml
├── .gitignore
├── .rspec
├── .rubocop.yml
├── .ruby-gemset
├── .ruby-version
├── .yardopts
├── CONTRIBUTING.md
├── COPYRIGHT
├── Changelog.md
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── Rakefile
├── app
└── controllers
│ └── diaspora_federation
│ ├── application_controller.rb
│ ├── fetch_controller.rb
│ ├── h_card_controller.rb
│ ├── receive_controller.rb
│ └── webfinger_controller.rb
├── bin
├── bundle
├── pronto
├── rails
├── rake
├── rspec
└── rubocop
├── config
├── initializers
│ ├── filter_parameter_logging.rb
│ └── mime_types.rb
└── routes.rb
├── diaspora_federation-json_schema.gemspec
├── diaspora_federation-rails.gemspec
├── diaspora_federation-test.gemspec
├── diaspora_federation.gemspec
├── docs
├── _config.yml
├── _entities
│ ├── account_deletion.md
│ ├── account_migration.md
│ ├── comment.md
│ ├── contact.md
│ ├── conversation.md
│ ├── embed.md
│ ├── event.md
│ ├── event_participation.md
│ ├── like.md
│ ├── location.md
│ ├── message.md
│ ├── participation.md
│ ├── photo.md
│ ├── poll.md
│ ├── poll_answer.md
│ ├── poll_participation.md
│ ├── post.md
│ ├── profile.md
│ ├── reshare.md
│ ├── retraction.md
│ └── status_message.md
├── _includes
│ ├── active_class.html
│ ├── discovery_tree.html
│ ├── entity_tree.html
│ ├── federation_tree.html
│ ├── top_navbar.html
│ └── warning_box.html
├── _layouts
│ └── default.html
├── assets
│ ├── css
│ │ ├── _pygments.scss
│ │ ├── _theme.scss
│ │ ├── _webfonts.scss
│ │ └── main.scss
│ ├── fonts
│ │ ├── FiraMono-Bold.eot
│ │ ├── FiraMono-Bold.ttf
│ │ ├── FiraMono-Bold.woff
│ │ ├── FiraMono-Regular.eot
│ │ ├── FiraMono-Regular.ttf
│ │ ├── FiraMono-Regular.woff
│ │ ├── FiraSans-Bold.eot
│ │ ├── FiraSans-Bold.ttf
│ │ ├── FiraSans-Bold.woff
│ │ ├── FiraSans-BoldItalic.eot
│ │ ├── FiraSans-BoldItalic.ttf
│ │ ├── FiraSans-BoldItalic.woff
│ │ ├── FiraSans-Italic.eot
│ │ ├── FiraSans-Italic.ttf
│ │ ├── FiraSans-Italic.woff
│ │ ├── FiraSans-Regular.eot
│ │ ├── FiraSans-Regular.ttf
│ │ └── FiraSans-Regular.woff
│ ├── images
│ │ └── favicon.ico
│ └── vendor
│ │ ├── css
│ │ ├── bootstrap-theme.min.css
│ │ ├── bootstrap-theme.min.css.map
│ │ ├── bootstrap.min.css
│ │ └── bootstrap.min.css.map
│ │ ├── fonts
│ │ ├── glyphicons-halflings-regular.eot
│ │ ├── glyphicons-halflings-regular.svg
│ │ ├── glyphicons-halflings-regular.ttf
│ │ ├── glyphicons-halflings-regular.woff
│ │ └── glyphicons-halflings-regular.woff2
│ │ └── js
│ │ ├── bootstrap.min.js
│ │ └── jquery-2.2.0.min.js
├── discovery
│ ├── hcard.md
│ └── webfinger.md
├── entities
│ └── index.md
├── federation
│ ├── diaspora_scheme.md
│ ├── encryption.md
│ ├── fetching.md
│ ├── magicsig.md
│ ├── relayable.md
│ ├── routes.md
│ ├── types.md
│ └── xml_serialization.md
├── index.md
└── schemas
│ └── federation_entities.json
├── lib
├── diaspora_federation.rb
├── diaspora_federation
│ ├── callbacks.rb
│ ├── discovery.rb
│ ├── discovery
│ │ ├── discovery.rb
│ │ ├── exceptions.rb
│ │ ├── h_card.rb
│ │ ├── web_finger.rb
│ │ └── xrd_document.rb
│ ├── engine.rb
│ ├── entities.rb
│ ├── entities
│ │ ├── account_deletion.rb
│ │ ├── account_migration.rb
│ │ ├── account_migration
│ │ │ └── signable.rb
│ │ ├── comment.rb
│ │ ├── contact.rb
│ │ ├── conversation.rb
│ │ ├── embed.rb
│ │ ├── event.rb
│ │ ├── event_participation.rb
│ │ ├── like.rb
│ │ ├── location.rb
│ │ ├── message.rb
│ │ ├── participation.rb
│ │ ├── person.rb
│ │ ├── photo.rb
│ │ ├── poll.rb
│ │ ├── poll_answer.rb
│ │ ├── poll_participation.rb
│ │ ├── post.rb
│ │ ├── profile.rb
│ │ ├── related_entity.rb
│ │ ├── relayable.rb
│ │ ├── reshare.rb
│ │ ├── retraction.rb
│ │ ├── signable.rb
│ │ └── status_message.rb
│ ├── entity.rb
│ ├── federation.rb
│ ├── federation
│ │ ├── diaspora_url_parser.rb
│ │ ├── fetcher.rb
│ │ ├── receiver.rb
│ │ ├── receiver
│ │ │ ├── abstract_receiver.rb
│ │ │ ├── exceptions.rb
│ │ │ ├── private.rb
│ │ │ └── public.rb
│ │ ├── sender.rb
│ │ └── sender
│ │ │ └── hydra_wrapper.rb
│ ├── http_client.rb
│ ├── logging.rb
│ ├── parsers.rb
│ ├── parsers
│ │ ├── base_parser.rb
│ │ ├── json_parser.rb
│ │ ├── relayable_json_parser.rb
│ │ ├── relayable_xml_parser.rb
│ │ └── xml_parser.rb
│ ├── properties_dsl.rb
│ ├── rails.rb
│ ├── salmon.rb
│ ├── salmon
│ │ ├── aes.rb
│ │ ├── encrypted_magic_envelope.rb
│ │ ├── exceptions.rb
│ │ └── magic_envelope.rb
│ ├── schemas.rb
│ ├── schemas
│ │ └── federation_entities.json
│ ├── test.rb
│ ├── test
│ │ ├── entity_generator.rb
│ │ └── factories.rb
│ ├── validators.rb
│ ├── validators
│ │ ├── account_deletion_validator.rb
│ │ ├── account_migration_validator.rb
│ │ ├── comment_validator.rb
│ │ ├── contact_validator.rb
│ │ ├── conversation_validator.rb
│ │ ├── embed_validator.rb
│ │ ├── event_participation_validator.rb
│ │ ├── event_validator.rb
│ │ ├── h_card_validator.rb
│ │ ├── like_validator.rb
│ │ ├── location_validator.rb
│ │ ├── message_validator.rb
│ │ ├── optional_aware_validator.rb
│ │ ├── participation_validator.rb
│ │ ├── person_validator.rb
│ │ ├── photo_validator.rb
│ │ ├── poll_answer_validator.rb
│ │ ├── poll_participation_validator.rb
│ │ ├── poll_validator.rb
│ │ ├── profile_validator.rb
│ │ ├── related_entity_validator.rb
│ │ ├── relayable_validator.rb
│ │ ├── reshare_validator.rb
│ │ ├── retraction_validator.rb
│ │ ├── rules
│ │ │ ├── birthday.rb
│ │ │ ├── boolean.rb
│ │ │ ├── diaspora_id.rb
│ │ │ ├── diaspora_id_list.rb
│ │ │ ├── guid.rb
│ │ │ ├── not_nil.rb
│ │ │ ├── public_key.rb
│ │ │ └── tag_count.rb
│ │ ├── status_message_validator.rb
│ │ └── web_finger_validator.rb
│ └── version.rb
└── tasks
│ └── build.rake
├── spec
├── controllers
│ └── diaspora_federation
│ │ ├── application_controller_spec.rb
│ │ ├── fetch_controller_spec.rb
│ │ ├── h_card_controller_spec.rb
│ │ ├── receive_controller_spec.rb
│ │ └── webfinger_controller_spec.rb
├── entities.rb
├── factories.rb
├── integration
│ └── comment_integration_spec.rb
├── lib
│ ├── diaspora_federation
│ │ ├── callbacks_spec.rb
│ │ ├── discovery
│ │ │ ├── discovery_spec.rb
│ │ │ ├── h_card_spec.rb
│ │ │ ├── web_finger_spec.rb
│ │ │ └── xrd_document_spec.rb
│ │ ├── entities
│ │ │ ├── account_deletion_spec.rb
│ │ │ ├── account_migration
│ │ │ │ └── signable_spec.rb
│ │ │ ├── account_migration_spec.rb
│ │ │ ├── comment_spec.rb
│ │ │ ├── contact_spec.rb
│ │ │ ├── conversation_spec.rb
│ │ │ ├── embed_spec.rb
│ │ │ ├── event_participation_spec.rb
│ │ │ ├── event_spec.rb
│ │ │ ├── like_spec.rb
│ │ │ ├── location_spec.rb
│ │ │ ├── message_spec.rb
│ │ │ ├── participation_spec.rb
│ │ │ ├── person_spec.rb
│ │ │ ├── photo_spec.rb
│ │ │ ├── poll_answer_spec.rb
│ │ │ ├── poll_participation_spec.rb
│ │ │ ├── poll_spec.rb
│ │ │ ├── profile_spec.rb
│ │ │ ├── related_entity_spec.rb
│ │ │ ├── relayable_spec.rb
│ │ │ ├── reshare_spec.rb
│ │ │ ├── retraction_spec.rb
│ │ │ ├── signable_spec.rb
│ │ │ └── status_message_spec.rb
│ │ ├── entity_spec.rb
│ │ ├── federation
│ │ │ ├── diaspora_url_parser_spec.rb
│ │ │ ├── fetcher_spec.rb
│ │ │ ├── receiver
│ │ │ │ ├── private_spec.rb
│ │ │ │ └── public_spec.rb
│ │ │ ├── receiver_spec.rb
│ │ │ ├── sender
│ │ │ │ └── hydra_wrapper_spec.rb
│ │ │ └── sender_spec.rb
│ │ ├── http_client_spec.rb
│ │ ├── parsers
│ │ │ ├── base_parser_spec.rb
│ │ │ ├── json_parser_spec.rb
│ │ │ ├── relayable_json_parser_spec.rb
│ │ │ ├── relayable_xml_parser_spec.rb
│ │ │ └── xml_parser_spec.rb
│ │ ├── properties_dsl_spec.rb
│ │ ├── salmon
│ │ │ ├── aes_spec.rb
│ │ │ ├── encrypted_magic_envelope_spec.rb
│ │ │ └── magic_envelope_spec.rb
│ │ ├── schemas_spec.rb
│ │ └── validators
│ │ │ ├── account_deletion_validator_spec.rb
│ │ │ ├── account_migration_validator_spec.rb
│ │ │ ├── comment_validator_spec.rb
│ │ │ ├── contact_validator_spec.rb
│ │ │ ├── conversation_validator_spec.rb
│ │ │ ├── embed_validator_spec.rb
│ │ │ ├── event_participation_validator_spec.rb
│ │ │ ├── event_validator_spec.rb
│ │ │ ├── h_card_validator_spec.rb
│ │ │ ├── like_validator_spec.rb
│ │ │ ├── location_validator_spec.rb
│ │ │ ├── message_validator_spec.rb
│ │ │ ├── optional_aware_validator_spec.rb
│ │ │ ├── participation_validator_spec.rb
│ │ │ ├── person_validator_spec.rb
│ │ │ ├── photo_validator_spec.rb
│ │ │ ├── poll_answer_validator_spec.rb
│ │ │ ├── poll_participation_validator_spec.rb
│ │ │ ├── poll_validator_spec.rb
│ │ │ ├── profile_validator_spec.rb
│ │ │ ├── related_entity_validator_spec.rb
│ │ │ ├── reshare_validator_spec.rb
│ │ │ ├── retraction_validator_spec.rb
│ │ │ ├── rules
│ │ │ ├── birthday_spec.rb
│ │ │ ├── boolean_spec.rb
│ │ │ ├── diaspora_id_list_spec.rb
│ │ │ ├── diaspora_id_spec.rb
│ │ │ ├── guid_spec.rb
│ │ │ ├── not_nil_spec.rb
│ │ │ ├── public_key_spec.rb
│ │ │ └── tag_count_spec.rb
│ │ │ ├── status_message_validator_spec.rb
│ │ │ └── web_finger_validator_spec.rb
│ └── diaspora_federation_spec.rb
├── routing
│ ├── fetch_routing_spec.rb
│ ├── receive_routing_spec.rb
│ └── webfinger_routing_spec.rb
├── spec_helper.rb
└── support
│ ├── fixture_builder.rb
│ ├── helper_methods.rb
│ ├── shared_entity_specs.rb
│ ├── shared_magic_envelope_specs.rb
│ ├── shared_parser_specs.rb
│ ├── shared_signable_specs.rb
│ └── shared_validator_specs.rb
└── test
├── dummy
├── README.rdoc
├── Rakefile
├── app
│ └── models
│ │ ├── entity.rb
│ │ └── person.rb
├── bin
│ ├── rails
│ ├── rake
│ └── setup
├── config.ru
├── config
│ ├── application.rb
│ ├── boot.rb
│ ├── environment.rb
│ ├── environments
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers
│ │ ├── backtrace_silencers.rb
│ │ ├── cookies_serializer.rb
│ │ ├── diaspora_federation.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── session_store.rb
│ │ └── wrap_parameters.rb
│ ├── routes.rb
│ └── secrets.yml
└── log
│ └── .keep
└── scripts
└── ci.sh
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | ---
2 | engines:
3 | rubocop:
4 | enabled: true
5 | channel: rubocop-1-22-3
6 | bundler-audit:
7 | enabled: true
8 | ratings:
9 | paths:
10 | - app/**
11 | - config/**
12 | - lib/**
13 | - spec/**
14 | - test/**
15 | - Gemfile.lock
16 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 2
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | push:
4 | branches:
5 | - develop
6 | - main
7 | - master
8 | pull_request:
9 |
10 | jobs:
11 | test:
12 | name: 'Ruby: ${{ matrix.ruby }}, Rails: ${{ matrix.rails }}'
13 | runs-on: ubuntu-latest
14 | strategy:
15 | fail-fast: false
16 | matrix:
17 | ruby:
18 | - "3.2"
19 | - "3.1"
20 | - "3.0"
21 | - "2.7"
22 | rails:
23 | - "7.0"
24 | - "6.1"
25 | - "6.0"
26 | - "5.2"
27 | - "none"
28 | exclude:
29 | - ruby: "3.2"
30 | rails: "5.2"
31 | - ruby: "3.1"
32 | rails: "5.2"
33 | - ruby: "3.0"
34 | rails: "5.2"
35 | env:
36 | RAILS_VERSION: ${{ matrix.rails }}
37 | BUNDLE_WITHOUT: development
38 | BUNDLE_DISABLE_SHARED_GEMS: true
39 | CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
40 | steps:
41 | - uses: actions/checkout@v3
42 | - name: Delete Gemfile.lock
43 | run: rm Gemfile.lock
44 | if: matrix.rails != '7.0' # Gemfile.lock is only generated for latest rails version
45 | - uses: ruby/setup-ruby@v1
46 | with:
47 | ruby-version: ${{ matrix.ruby }}
48 | bundler-cache: true
49 | - name: Run tests
50 | run: test/scripts/ci.sh
51 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .bundle/
2 | vendor/bundle
3 | pkg/
4 |
5 | # IDE files
6 | .idea
7 |
8 | # coverage reports
9 | coverage
10 |
11 | # documentation
12 | rdoc
13 | doc
14 | .yardoc/
15 |
16 | # Temporary files
17 | .DS_Store
18 | *.swp
19 | *~
20 | *.directory
21 |
22 | # dummmy app
23 | test/dummy/log/*.log
24 | test/dummy/log/*.log*
25 | test/dummy/tmp
26 |
27 | rspec-persistence.txt
28 |
29 | .rake_tasks
30 |
31 | # jekyll
32 | docs/_site
33 | docs/.sass-cache
34 | docs/.jekyll-metadata
35 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --format Fuubar
2 | --color
3 | --require spec_helper
4 |
--------------------------------------------------------------------------------
/.ruby-gemset:
--------------------------------------------------------------------------------
1 | diaspora-federation
2 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 3.2
2 |
--------------------------------------------------------------------------------
/.yardopts:
--------------------------------------------------------------------------------
1 | --quiet
2 | -
3 | Changelog.md
4 | CONTRIBUTING.md
5 | LICENSE
6 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to our federation
2 |
3 | First of all: thank you very much for helping us out! Since the federation layer is a very crucial part of diaspora\*, contributing has some rules, depending on what you want to contribute.
4 |
5 | ## Things you need to know before contributing
6 |
7 | If you want to get in touch with other diaspora\* developers, [check our wiki][how-we-communicate] for information on how we communicate. Feel free to ask if you have any questions!
8 |
9 | As with the main diaspora\* repository, everyone interacting with our code, issue trackers, chat rooms, mailing lists, the wiki, and the discourse forum is expected to follow the [diaspora\* code of conduct][code-of-conduct].
10 |
11 | ## Report a security issue
12 |
13 | Found a security issue in some parts of the protocol or its implementation? Please disclose it responsibly. We have a team of developers listening to [security@diasporafoundation.org][sec-mail]. The PGP fingerprint is [AB0D AB02 0FC5 D398 03AB 3CE1 6F70 243F 27AD 886A][pgp].
14 |
15 | ## Improve the documentation
16 |
17 | Feel free to open a pull request right away if you would like to improve the inlined code documentation or the dedicated federation protocol documentation.
18 |
19 | ## Changing implementations or altering fields
20 |
21 | If you want to change implementations of existing functions or you would like to suggest a change in the federation protocol, please open an issue *before doing anything else*. Try to describe your idea and why you think the implementation or the protocol should change as close as possible. Most changes will have to get discussed in a larger group before implementing them, so it's important to start those discussions before writing any code.
22 |
23 | [code-of-conduct]: https://github.com/diaspora/diaspora/blob/develop/CODE_OF_CONDUCT.md
24 | [how-we-communicate]: https://wiki.diasporafoundation.org/How_we_communicate
25 | [pgp]: https://pgp.mit.edu/pks/lookup?op=get&search=0x6F70243F27AD886A
26 | [sec-mail]: mailto:security@diasporafoundation.org
27 |
--------------------------------------------------------------------------------
/COPYRIGHT:
--------------------------------------------------------------------------------
1 | diaspora* federation library
2 | Copyright (C) 2015 Benjamin Neff
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU Affero General Public License as
6 | published by the Free Software Foundation, either version 3 of the
7 | License, or (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU Affero General Public License for more details.
13 |
14 | Some parts are based on an older federation gem from Florian Staudacher:
15 | https://github.com/Raven24/diaspora-federation
16 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | begin
4 | require "bundler/setup"
5 | rescue LoadError
6 | puts "You must `gem install bundler` and `bundle install` to run rake tasks"
7 | end
8 |
9 | require "rdoc/task"
10 |
11 | RDoc::Task.new(:rdoc) do |rdoc|
12 | rdoc.rdoc_dir = "rdoc"
13 | rdoc.title = "DiasporaFederation"
14 | rdoc.options << "--line-numbers"
15 | rdoc.rdoc_files.include("lib/**/*.rb")
16 | end
17 |
18 | if defined?(Rails)
19 | APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
20 | load "rails/tasks/engine.rake"
21 | load "rails/tasks/statistics.rake"
22 |
23 | Rails.application.load_tasks
24 | else
25 | require "rspec/core/rake_task"
26 | RSpec::Core::RakeTask.new(:spec)
27 | FileList["lib/tasks/**/*.rake"].each {|task| load(task) }
28 | end
29 |
30 | Bundler::GemHelper.install_tasks name: "diaspora_federation"
31 |
32 | desc "Run all tests"
33 | task test: :spec
34 | task default: :test
35 |
--------------------------------------------------------------------------------
/app/controllers/diaspora_federation/application_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | # Base controller for all DiasporaFederation controllers
5 | class ApplicationController < ActionController::Base
6 | before_action :set_locale
7 |
8 | # Fix locale leakage from other requests.
9 | # Set "en" as locale for every federation request.
10 | def set_locale
11 | I18n.locale = :en
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/app/controllers/diaspora_federation/fetch_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_dependency "diaspora_federation/application_controller"
4 |
5 | module DiasporaFederation
6 | # This controller processes fetch requests.
7 | class FetchController < ApplicationController
8 | # Returns the fetched entity or a redirect
9 | #
10 | # GET /fetch/:type/:guid
11 | def fetch
12 | entity = fetch_public_entity
13 | if entity
14 | magic_env = create_magic_envelope(entity)
15 | if magic_env
16 | render xml: magic_env, content_type: "application/magic-envelope+xml"
17 | else
18 | redirect_url = DiasporaFederation.callbacks.trigger(:fetch_person_url_to,
19 | entity.author, "/fetch/#{params[:type]}/#{params[:guid]}")
20 | redirect_to redirect_url, allow_other_host: true
21 | end
22 | else
23 | head :not_found
24 | end
25 | end
26 |
27 | private
28 |
29 | def fetch_public_entity
30 | type = DiasporaFederation::Entity.entity_class(params[:type]).to_s.rpartition("::").last
31 | DiasporaFederation.callbacks.trigger(:fetch_public_entity, type, params[:guid])
32 | end
33 |
34 | def create_magic_envelope(entity)
35 | privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key, entity.author)
36 | Salmon::MagicEnvelope.new(entity, entity.author).envelop(privkey) if privkey
37 | end
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/app/controllers/diaspora_federation/h_card_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_dependency "diaspora_federation/application_controller"
4 |
5 | module DiasporaFederation
6 | # This controller generates the hcard.
7 | class HCardController < ApplicationController
8 | # Returns the hcard of the user
9 | #
10 | # GET /hcard/users/:guid
11 | def hcard
12 | person_hcard = DiasporaFederation.callbacks.trigger(:fetch_person_for_hcard, params[:guid])
13 |
14 | if person_hcard.nil?
15 | head :not_found
16 | else
17 | logger.info "hcard profile request for: #{person_hcard.nickname}:#{person_hcard.guid}"
18 | # rubocop:disable Rails/OutputSafety
19 | render html: person_hcard.to_html.html_safe
20 | # rubocop:enable Rails/OutputSafety
21 | end
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/app/controllers/diaspora_federation/receive_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_dependency "diaspora_federation/application_controller"
4 |
5 | module DiasporaFederation
6 | # This controller processes receiving messages.
7 | class ReceiveController < ApplicationController
8 | skip_forgery_protection
9 |
10 | # Receives public messages
11 | #
12 | # POST /receive/public
13 | def public
14 | data = request.body.read
15 | logger.debug data
16 |
17 | DiasporaFederation.callbacks.trigger(:queue_public_receive, data)
18 |
19 | head :accepted
20 | end
21 |
22 | # Receives private messages for a user
23 | #
24 | # POST /receive/users/:guid
25 | def private
26 | data = request.body.read
27 | logger.debug data
28 |
29 | success = DiasporaFederation.callbacks.trigger(:queue_private_receive, params[:guid], data)
30 |
31 | head success ? :accepted : :not_found
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 | #
4 | # This file was generated by Bundler.
5 | #
6 | # The application 'bundler' is installed as part of a gem, and
7 | # this file is here to facilitate running it.
8 | #
9 |
10 | require "pathname"
11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12 | Pathname.new(__FILE__).realpath)
13 |
14 | require "rubygems"
15 |
16 | load Gem.bin_path("bundler", "bundle")
17 |
--------------------------------------------------------------------------------
/bin/pronto:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 | #
4 | # This file was generated by Bundler.
5 | #
6 | # The application 'pronto' is installed as part of a gem, and
7 | # this file is here to facilitate running it.
8 | #
9 |
10 | require "pathname"
11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12 | Pathname.new(__FILE__).realpath)
13 |
14 | require "rubygems"
15 | require "bundler/setup"
16 |
17 | load Gem.bin_path("pronto", "pronto")
18 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # This command will automatically be run when you run "rails" with Rails gems
3 | # installed from the root of your application.
4 |
5 | ENGINE_ROOT = File.expand_path("..", __dir__)
6 | ENGINE_PATH = File.expand_path("../lib/diaspora_federation/engine", __dir__)
7 | APP_PATH = File.expand_path("../test/dummy/config/application", __dir__)
8 |
9 | # Set up gems listed in the Gemfile.
10 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
11 | require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
12 |
13 | require "rails/all"
14 | require "rails/engine/commands"
15 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 | #
4 | # This file was generated by Bundler.
5 | #
6 | # The application 'rake' is installed as part of a gem, and
7 | # this file is here to facilitate running it.
8 | #
9 |
10 | require "pathname"
11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12 | Pathname.new(__FILE__).realpath)
13 |
14 | require "rubygems"
15 | require "bundler/setup"
16 |
17 | load Gem.bin_path("rake", "rake")
18 |
--------------------------------------------------------------------------------
/bin/rspec:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 | #
4 | # This file was generated by Bundler.
5 | #
6 | # The application 'rspec' is installed as part of a gem, and
7 | # this file is here to facilitate running it.
8 | #
9 |
10 | require "pathname"
11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12 | Pathname.new(__FILE__).realpath)
13 |
14 | require "rubygems"
15 | require "bundler/setup"
16 |
17 | load Gem.bin_path("rspec-core", "rspec")
18 |
--------------------------------------------------------------------------------
/bin/rubocop:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 | #
4 | # This file was generated by Bundler.
5 | #
6 | # The application 'rubocop' is installed as part of a gem, and
7 | # this file is here to facilitate running it.
8 | #
9 |
10 | require "pathname"
11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12 | Pathname.new(__FILE__).realpath)
13 |
14 | require "rubygems"
15 | require "bundler/setup"
16 |
17 | load Gem.bin_path("rubocop", "rubocop")
18 |
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Don't log received xml data.
4 | Rails.application.config.filter_parameters += %i[xml aes_key encrypted_magic_envelope]
5 |
--------------------------------------------------------------------------------
/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # mime types for webfinger
4 | Mime::Type.register "application/jrd+json", :jrd
5 | Mime::Type.register "application/xrd+xml", :xrd
6 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | DiasporaFederation::Engine.routes.draw do
4 | controller :receive do
5 | post "receive/public" => :public, :as => "receive_public"
6 | post "receive/users/:guid" => :private, :as => "receive_private"
7 | end
8 |
9 | controller :fetch do
10 | get "fetch/:type/:guid" => :fetch, :as => "fetch", :guid => /#{Validation::Rule::Guid::VALID_CHARS}/
11 | end
12 |
13 | controller :webfinger do
14 | get ".well-known/webfinger" => :webfinger, :as => "webfinger"
15 | end
16 |
17 | controller :h_card do
18 | get "hcard/users/:guid" => :hcard, :as => "hcard"
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/diaspora_federation-json_schema.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | $LOAD_PATH.push File.expand_path("lib", __dir__)
4 |
5 | # Maintain your gem's version:
6 | require "diaspora_federation/version"
7 |
8 | # Describe your gem and declare its dependencies:
9 | Gem::Specification.new do |s|
10 | s.name = "diaspora_federation-json_schema"
11 | s.version = DiasporaFederation::VERSION
12 | s.authors = ["Benjamin Neff", "cmrd Senya"]
13 | s.email = ["benjamin@coding4.coffee", "senya@riseup.net"]
14 | s.homepage = "https://github.com/diaspora/diaspora_federation"
15 | s.summary = "diaspora* federation json schemas"
16 | s.description = "This gem provides JSON schemas (currently one schema) for " \
17 | "validating JSON serialized federation objects."
18 | s.license = "AGPL-3.0"
19 | s.metadata = {
20 | "rubygems_mfa_required" => "true"
21 | }
22 |
23 | s.files = Dir["lib/diaspora_federation/schemas.rb", "lib/diaspora_federation/schemas/*.json"]
24 |
25 | s.required_ruby_version = ">= 2.7"
26 | end
27 |
--------------------------------------------------------------------------------
/diaspora_federation-rails.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | $LOAD_PATH.push File.expand_path("lib", __dir__)
4 |
5 | # Maintain your gem's version:
6 | require "diaspora_federation/version"
7 |
8 | # Describe your gem and declare its dependencies:
9 | Gem::Specification.new do |s|
10 | s.name = "diaspora_federation-rails"
11 | s.version = DiasporaFederation::VERSION
12 | s.authors = ["Benjamin Neff"]
13 | s.email = ["benjamin@coding4.coffee"]
14 | s.homepage = "https://github.com/diaspora/diaspora_federation"
15 | s.summary = "diaspora* federation rails engine"
16 | s.description = "A rails engine that adds the diaspora* federation protocol to a rails app"
17 | s.license = "AGPL-3.0"
18 | s.metadata = {
19 | "rubygems_mfa_required" => "true"
20 | }
21 |
22 | s.files = Dir["app/**/*", "config/routes.rb", "config/initializers/*",
23 | "lib/diaspora_federation/{engine,rails}.rb", "LICENSE", "README.md", "Changelog.md"]
24 |
25 | s.required_ruby_version = ">= 2.7"
26 |
27 | s.add_dependency "actionpack", ">= 5.2", "< 8"
28 |
29 | s.add_dependency "diaspora_federation", DiasporaFederation::VERSION
30 | end
31 |
--------------------------------------------------------------------------------
/diaspora_federation-test.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | $LOAD_PATH.push File.expand_path("lib", __dir__)
4 |
5 | # Maintain your gem's version:
6 | require "diaspora_federation/version"
7 |
8 | # Describe your gem and declare its dependencies:
9 | Gem::Specification.new do |s|
10 | s.name = "diaspora_federation-test"
11 | s.version = DiasporaFederation::VERSION
12 | s.authors = ["Benjamin Neff"]
13 | s.email = ["benjamin@coding4.coffee"]
14 | s.homepage = "https://github.com/diaspora/diaspora_federation"
15 | s.summary = "diaspora* federation test utils"
16 | s.description = "This gem provides some supplimentary code (factory definitions), that" \
17 | "helps to build tests for users of the diaspora_federation gem."
18 | s.license = "AGPL-3.0"
19 | s.metadata = {
20 | "rubygems_mfa_required" => "true"
21 | }
22 |
23 | s.files = Dir["lib/diaspora_federation/test.rb", "lib/diaspora_federation/test/*"]
24 |
25 | s.required_ruby_version = ">= 2.7"
26 |
27 | s.add_dependency "diaspora_federation", DiasporaFederation::VERSION
28 | s.add_dependency "fabrication", "~> 2.29"
29 | s.add_dependency "uuid", "~> 2.3", ">= 2.3.8"
30 | end
31 |
--------------------------------------------------------------------------------
/diaspora_federation.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | $LOAD_PATH.push File.expand_path("lib", __dir__)
4 |
5 | # Maintain your gem's version:
6 | require "diaspora_federation/version"
7 |
8 | # Describe your gem and declare its dependencies:
9 | Gem::Specification.new do |s|
10 | s.name = "diaspora_federation"
11 | s.version = DiasporaFederation::VERSION
12 | s.authors = ["Benjamin Neff"]
13 | s.email = ["benjamin@coding4.coffee"]
14 | s.homepage = "https://github.com/diaspora/diaspora_federation"
15 | s.summary = "diaspora* federation library"
16 | s.description = "This gem provides the functionality for de-/serialization and " \
17 | "de-/encryption of Entities in the protocols used for communication " \
18 | "among the various installations of Diaspora*"
19 | s.license = "AGPL-3.0"
20 | s.metadata = {
21 | "rubygems_mfa_required" => "true"
22 | }
23 |
24 | s.files = Dir["lib/**/*", "LICENSE", "README.md", "Changelog.md"] -
25 | Dir["lib/diaspora_federation/{engine,rails,schemas,test}.rb",
26 | "lib/diaspora_federation/schemas/*",
27 | "lib/diaspora_federation/test/*",
28 | "lib/tasks/*.rake"]
29 |
30 | s.required_ruby_version = ">= 2.7"
31 |
32 | s.add_dependency "faraday", ">= 1.0", "< 3"
33 | s.add_dependency "faraday-follow_redirects", "~> 0.3"
34 | s.add_dependency "nokogiri", "~> 1.6", ">= 1.6.8"
35 | s.add_dependency "typhoeus", "~> 1.0"
36 | s.add_dependency "valid", "~> 1.0"
37 | end
38 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | url: "https://diaspora.github.io" # the base hostname & protocol
2 | baseurl: "/diaspora_federation" # the subpath
3 | contribute_url: "https://github.com/diaspora/diaspora_federation/blob/develop/CONTRIBUTING.md"
4 |
5 | sass:
6 | sass_dir: assets/css
7 | style: nested
8 | deploy_style: nested
9 |
10 | collections:
11 | entities:
12 | output: true
13 |
14 | kramdown:
15 | toc_levels: 2..2
16 |
17 | defaults:
18 | -
19 | scope:
20 | path: ""
21 | values:
22 | layout: "default"
23 | title: ""
24 |
--------------------------------------------------------------------------------
/docs/_entities/account_deletion.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: AccountDeletion
3 | ---
4 |
5 | This entity is sent when a person closed the account.
6 |
7 | ## Properties
8 |
9 | | Property | Type | Description |
10 | | -------- | ---------------------------- | ---------------------------------------- |
11 | | `author` | [diaspora\* ID][diaspora-id] | The diaspora\* ID of the closed account. |
12 |
13 | ## Example
14 |
15 | ~~~xml
16 |
17 | alice@example.org
18 |
19 | ~~~
20 |
21 | [diaspora-id]: {{ site.baseurl }}/federation/types.html#diaspora-id
22 |
--------------------------------------------------------------------------------
/docs/_entities/contact.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Contact
3 | ---
4 |
5 | This entity represents a contact state with another person.
6 |
7 | When `blocking` is `true`, `following` and `sharing` need to be `false` (and the other way around).
8 |
9 | ## Properties
10 |
11 | | Property | Type | Description |
12 | | ----------- | ---------------------------- | --------------------------------------------------- |
13 | | `author` | [diaspora\* ID][diaspora-id] | The diaspora\* ID of the sender of the contact. |
14 | | `recipient` | [diaspora\* ID][diaspora-id] | The diaspora\* ID of the recipient. |
15 | | `following` | [Boolean][boolean] | `true` if the author is following the recipient. |
16 | | `sharing` | [Boolean][boolean] | `true` if the author is sharing with the recipient. |
17 |
18 | ## Optional Properties
19 |
20 | | Property | Type | Description |
21 | | ---------- | ------------------ | ----------------------------------------------- |
22 | | `blocking` | [Boolean][boolean] | `true` if the author is blocking the recipient. |
23 |
24 | ## Example
25 |
26 | ~~~xml
27 |
28 | alice@example.org
29 | bob@example.com
30 | true
31 | true
32 | false
33 |
34 | ~~~
35 |
36 | [diaspora-id]: {{ site.baseurl }}/federation/types.html#diaspora-id
37 | [boolean]: {{ site.baseurl }}/federation/types.html#boolean
38 |
--------------------------------------------------------------------------------
/docs/_entities/location.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Location
3 | ---
4 |
5 | This entity represents the location data, it is nested in a [StatusMessage][status_message].
6 |
7 | ## Properties
8 |
9 | | Property | Type (Length) | Description |
10 | | --------- | ---------------------- | ------------------------------------------------------------------------ |
11 | | `address` | [String][string] (255) | A string describing your location, e.g. a city name, a street name, etc. |
12 | | `lat` | [Float][float] | The geographical latitude of your location. |
13 | | `lng` | [Float][float] | The geographical longitude of your location. |
14 |
15 | ## Example
16 |
17 | ~~~xml
18 |
19 | Vienna, Austria
20 | 48.208174
21 | 16.373819
22 |
23 | ~~~
24 |
25 | [string]: {{ site.baseurl }}/federation/types.html#string
26 | [float]: {{ site.baseurl }}/federation/types.html#float
27 | [status_message]: {{ site.baseurl }}/entities/status_message.html
28 |
--------------------------------------------------------------------------------
/docs/_entities/message.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Message
3 | ---
4 |
5 | This entity represents a private message exchanged in private conversation. It can be nested in a
6 | [Conversation][conversation] if it is the first message.
7 |
8 | ## Properties
9 |
10 | | Property | Type (Length) | Editable | Description |
11 | | ------------------- | ---------------------------- |:--------:| ----------------------------------------------- |
12 | | `author` | [diaspora\* ID][diaspora-id] | ✘ | The diaspora\* ID of the author of the message. |
13 | | `guid` | [GUID][guid] | ✘ | The GUID of the message. |
14 | | `conversation_guid` | [GUID][guid] | ✘ | The GUID of the [Conversation][conversation]. |
15 | | `text` | [Markdown][markdown] (65535) | ✔ | The message text. |
16 | | `created_at` | [Timestamp][timestamp] | ✘ | The create timestamp of the message. |
17 |
18 | ## Optional Properties
19 |
20 | | Property | Type (Length) | Editable | Description |
21 | | -------------------- | ---------------------- |:--------:| ------------------------------------------ |
22 | | `edited_at` | [Timestamp][timestamp] | ✔ | The timestamp when the message was edited. |
23 |
24 | ## Example
25 |
26 | ~~~xml
27 |
28 | alice@example.org
29 | 5cc5692029eb013487753131731751e9
30 | 9b1376a029eb013487753131731751e9
31 | this is a very informative text
32 | 2016-07-11T23:17:48Z
33 |
34 | ~~~
35 |
36 | [diaspora-id]: {{ site.baseurl }}/federation/types.html#diaspora-id
37 | [guid]: {{ site.baseurl }}/federation/types.html#guid
38 | [markdown]: {{ site.baseurl }}/federation/types.html#markdown
39 | [timestamp]: {{ site.baseurl }}/federation/types.html#timestamp
40 | [conversation]: {{ site.baseurl }}/entities/conversation.html
41 |
--------------------------------------------------------------------------------
/docs/_entities/participation.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Participation
3 | ---
4 |
5 | A participation is sent to subscribe a person on updates for some [Post][post].
6 |
7 | The `parent_type` can only be a [Post][post] (if it's a [StatusMessage][status_message] or [Reshare][reshare])
8 |
9 | ## Properties
10 |
11 | | Property | Type | Description |
12 | | ------------- | ---------------------------- | ----------------------------------------------------- |
13 | | `author` | [diaspora\* ID][diaspora-id] | The diaspora\* ID of the author of the participation. |
14 | | `guid` | [GUID][guid] | The GUID of the participation. |
15 | | `parent_guid` | [GUID][guid] | The GUID of the parent entity. |
16 | | `parent_type` | [Type][type] | The entity type of the parent. |
17 |
18 | ## Example
19 |
20 | ~~~xml
21 |
22 | alice@example.org
23 | 0840a9b029f6013487753131731751e9
24 | Post
25 | c3893bf029e7013487753131731751e9
26 |
27 | ~~~
28 |
29 | [diaspora-id]: {{ site.baseurl }}/federation/types.html#diaspora-id
30 | [guid]: {{ site.baseurl }}/federation/types.html#guid
31 | [type]: {{ site.baseurl }}/federation/types.html#type
32 | [post]: {{ site.baseurl }}/entities/post.html
33 | [status_message]: {{ site.baseurl }}/entities/status_message.html
34 | [reshare]: {{ site.baseurl }}/entities/reshare.html
35 |
--------------------------------------------------------------------------------
/docs/_entities/poll.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Poll
3 | ---
4 |
5 | This entity represents a poll, it is nested in a [StatusMessage][status_message].
6 |
7 | ## Properties
8 |
9 | | Property | Type (Length) | Description |
10 | | ------------- | -------------------------- | ------------------------------ |
11 | | `guid` | [GUID][guid] | The GUID of the poll. |
12 | | `question` | [String][string] (255) | The question of the poll. |
13 | | `poll_answer` | [PollAnswer][poll_answer]s | At least 2 nested PollAnswers. |
14 |
15 | ## Example
16 |
17 | ~~~xml
18 |
19 | 2a22d6c029e9013487753131731751e9
20 | Select an answer
21 |
22 | 2a22db2029e9013487753131731751e9
23 | Yes
24 |
25 |
26 | 2a22e5e029e9013487753131731751e9
27 | No
28 |
29 |
30 | 2a22eca029e9013487753131731751e9
31 | Maybe
32 |
33 |
34 | ~~~
35 |
36 | [guid]: {{ site.baseurl }}/federation/types.html#guid
37 | [string]: {{ site.baseurl }}/federation/types.html#string
38 | [poll_answer]: {{ site.baseurl }}/entities/poll_answer.html
39 | [status_message]: {{ site.baseurl }}/entities/status_message.html
40 |
--------------------------------------------------------------------------------
/docs/_entities/poll_answer.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: PollAnswer
3 | ---
4 |
5 | This entity represents a answer of a [Poll][poll].
6 |
7 | ## Properties
8 |
9 | | Property | Type (Length) | Description |
10 | | -------- | ---------------------- | ----------------------- |
11 | | `guid` | [GUID][guid] | The GUID of the answer. |
12 | | `answer` | [String][string] (255) | The answer text. |
13 |
14 | ## Example
15 |
16 | ~~~xml
17 |
18 | 2a22db2029e9013487753131731751e9
19 | Yes
20 |
21 | ~~~
22 |
23 | [guid]: {{ site.baseurl }}/federation/types.html#guid
24 | [string]: {{ site.baseurl }}/federation/types.html#string
25 | [poll]: {{ site.baseurl }}/entities/poll.html
26 |
--------------------------------------------------------------------------------
/docs/_entities/poll_participation.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: PollParticipation
3 | ---
4 |
5 | This entity represents a participation in a [Poll][poll].
6 |
7 | See also: [Relayable][relayable]
8 |
9 | ## Properties
10 |
11 | | Property | Type | Description |
12 | | ------------------------- | ---------------------------- | ---------------------------------------------------------- |
13 | | `author` | [diaspora\* ID][diaspora-id] | The diaspora\* ID of the author of the poll participation. |
14 | | `guid` | [GUID][guid] | The GUID of the poll participation. |
15 | | `parent_guid` | [GUID][guid] | The GUID of the [Poll][poll]. |
16 | | `poll_answer_guid` | [GUID][guid] | The GUID of the [PollAnswer][poll_answer]. |
17 | | `author_signature` | [Signature][signature] | The signature from the author of the poll participation. |
18 |
19 | ## Examples
20 |
21 | ~~~xml
22 |
23 | f1eb866029f7013487753131731751e9
24 | 2a22d6c029e9013487753131731751e9
25 | alice@example.org
26 | 2a22db2029e9013487753131731751e9
27 | dT6KbT7kp0bE+s3//ZErxO1wvVIqtD0lY67i81+dO43B4D2m5kjCdzW240eWt/jZmcHIsdxXf4WHNdrb6ZDnamA8I1FUVnLjHA9xexBITQsSLXrcV88UdammSmmOxl1Ac4VUXqFpdavm6a7/MwOJ7+JHP8TbUO9siN+hMfgUbtY=
28 |
29 | ~~~
30 |
31 | [diaspora-id]: {{ site.baseurl }}/federation/types.html#diaspora-id
32 | [guid]: {{ site.baseurl }}/federation/types.html#guid
33 | [signature]: {{ site.baseurl }}/federation/types.html#signature
34 | [poll]: {{ site.baseurl }}/entities/poll.html
35 | [poll_answer]: {{ site.baseurl }}/entities/poll_answer.html
36 | [relayable]: {{ site.baseurl }}/federation/relayable.html
37 |
--------------------------------------------------------------------------------
/docs/_entities/post.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Post
3 | ---
4 |
5 | This is the abstract parent type of [StatusMessage][status_message] and currently still [Reshare][reshare].
6 |
7 | {% include warning_box.html
8 | title="Future of reshares"
9 | content="
Reshare will not inherit from Post in the future anymore! More information about this
10 | can be found here or
11 | in this issue.
"
12 | %}
13 |
14 | ## Common Properties
15 |
16 | | Property | Type (Length) | Description |
17 | | ------------ | ---------------------------- | -------------------------------------------- |
18 | | `author` | [diaspora\* ID][diaspora-id] | The diaspora\* ID of the author of the post. |
19 | | `guid` | [GUID][guid] | The GUID of the post. |
20 | | `created_at` | [Timestamp][timestamp] | The create timestamp of the post. |
21 | | `public` | [Boolean][boolean] | `true` if the post is public. |
22 |
23 | ## Common Optional Properties
24 |
25 | | Property | Type (Length) | Description |
26 | | ----------------------- | ---------------------- | -------------------------------------------------- |
27 | | `provider_display_name` | [String][string] (255) | The means by which the author has posted the post. |
28 |
29 | [diaspora-id]: {{ site.baseurl }}/federation/types.html#diaspora-id
30 | [guid]: {{ site.baseurl }}/federation/types.html#guid
31 | [timestamp]: {{ site.baseurl }}/federation/types.html#timestamp
32 | [boolean]: {{ site.baseurl }}/federation/types.html#boolean
33 | [string]: {{ site.baseurl }}/federation/types.html#string
34 | [status_message]: {{ site.baseurl }}/entities/status_message.html
35 | [reshare]: {{ site.baseurl }}/entities/reshare.html
36 |
--------------------------------------------------------------------------------
/docs/_entities/retraction.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Retraction
3 | ---
4 |
5 | This entity represents a claim of deletion of a previously federated entity.
6 |
7 | ## Properties
8 |
9 | | Property | Type | Description |
10 | | ------------- | ---------------------------- | ------------------------------------------------- |
11 | | `author` | [diaspora\* ID][diaspora-id] | The diaspora\* ID of the who claims the deletion. |
12 | | `target_guid` | [GUID][guid] | The GUID of the entity to delete. |
13 | | `target_type` | [Type][type] | The type of the entity to delete. |
14 |
15 | ## Example
16 |
17 | ~~~xml
18 |
19 | alice@example.org
20 | 8d89e1f029f6013487753131731751e9
21 | Post
22 |
23 | ~~~
24 |
25 | [diaspora-id]: {{ site.baseurl }}/federation/types.html#diaspora-id
26 | [guid]: {{ site.baseurl }}/federation/types.html#guid
27 | [type]: {{ site.baseurl }}/federation/types.html#type
28 |
--------------------------------------------------------------------------------
/docs/_includes/active_class.html:
--------------------------------------------------------------------------------
1 | {% if page.url == include.url %}active{% endif %}
2 |
--------------------------------------------------------------------------------
/docs/_includes/discovery_tree.html:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/docs/_includes/entity_tree.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/docs/_includes/federation_tree.html:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/docs/_includes/top_navbar.html:
--------------------------------------------------------------------------------
1 |
38 |
--------------------------------------------------------------------------------
/docs/_includes/warning_box.html:
--------------------------------------------------------------------------------
1 |
2 |
{{ include.title }}
3 |
{{ include.content }}
4 |
5 |
--------------------------------------------------------------------------------
/docs/_layouts/default.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | {% capture page_title %}
10 | {% if page.title != "" %}
11 | {{ page.title }} - diaspora* federation protocol
12 | {% else %}
13 | diaspora* federation protocol
14 | {% endif %}
15 | {% endcapture %}
16 | {{ page_title | strip }}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | {% include top_navbar.html %}
27 |
28 |
29 |
30 |
44 |
45 |
46 | {% if page.title != "" %}
47 |
{{ page.title }}
48 | {% endif %}
49 |
50 | {{ content }}
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/docs/assets/css/_theme.scss:
--------------------------------------------------------------------------------
1 | body {
2 | color: #bfbfbf;
3 | background-color: #181818;
4 | }
5 |
6 | .navbar-default {
7 | background-color: #0f0f0f;
8 | border-color: #222;
9 |
10 | .navbar-nav > {
11 | .active,
12 | .open {
13 | > a {
14 | &,
15 | &:focus,
16 | &:hover {
17 | color: #fff;
18 | background-color: #555;
19 | }
20 | }
21 |
22 | .dropdown-menu > {
23 | .active > a {
24 | &,
25 | &:focus,
26 | &:hover {
27 | color: #fff;
28 | background-color: #555;
29 | }
30 | }
31 |
32 | li > a {
33 | &:focus,
34 | &:hover {
35 | color: #fff;
36 | }
37 | }
38 | }
39 | }
40 |
41 | li > a {
42 | &:focus,
43 | &:hover {
44 | color: #fff;
45 | }
46 | }
47 | }
48 | }
49 |
50 | .nav > li > a {
51 | &:focus,
52 | &:hover {
53 | color: #fff;
54 | background-color: #555;
55 | }
56 | }
57 |
58 | code, pre {
59 | color: #bfbfbf;
60 | background-color: #181818;
61 | border: 1px solid #474747;
62 | }
63 | pre code {
64 | border: 0;
65 | }
66 |
67 | .panel {
68 | background-color: #181818;
69 | }
70 | .panel-warning {
71 | border-color: #645a1b;
72 |
73 | > .panel-heading {
74 | color: #cebc4a;
75 | background-color: #645a1b;
76 | border-color: #141205;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/docs/assets/css/main.scss:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | @import "pygments";
5 | @import "webfonts";
6 | @import "theme";
7 |
8 | .container-fluid {
9 | max-width: 1200px;
10 | }
11 |
12 | body {
13 | font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
14 | padding-bottom: 70px;
15 | padding-top: 20px;
16 | }
17 |
18 | .navbar {
19 | margin-bottom: 20px;
20 | }
21 |
22 | .sidebar {
23 | .nav-header {
24 | margin-left: 15px;
25 | margin-top: 25px;
26 | }
27 | }
28 |
29 | .docbody {
30 | h1:first-child {
31 | margin-top: 0;
32 | }
33 |
34 | h2 {
35 | border-top: 1px solid #222;
36 | margin-top: 30px;
37 | padding-top: 25px;
38 | }
39 |
40 | pre {
41 | max-height: 300px;
42 |
43 | code {
44 | font-family: "Fira Mono", monospace, monospace;
45 | overflow: auto;
46 | white-space: pre;
47 | word-wrap: normal;
48 | }
49 | }
50 |
51 | .panel-body p:last-child {
52 | margin-bottom: 0;
53 | }
54 |
55 | /**
56 | * Based on the Twitter Bootstrap .table styles. See
57 | * https://github.com/twbs/bootstrap/blob/master/less/tables.less
58 | */
59 | table {
60 | margin-bottom: 20px;
61 | max-width: 100%;
62 | width: 100%;
63 |
64 | thead tr th {
65 | border-bottom: 2px solid #474747;
66 | line-height: 1.42857143;
67 | padding: 8px;
68 | vertical-align: bottom;
69 | }
70 |
71 | tbody tr {
72 | td {
73 | border-top: 1px solid #474747;
74 | line-height: 1.42857143;
75 | padding: 8px;
76 | vertical-align: top;
77 | }
78 |
79 | &:nth-of-type(2n+1) {
80 | background-color: #222;
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraMono-Bold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraMono-Bold.eot
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraMono-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraMono-Bold.ttf
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraMono-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraMono-Bold.woff
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraMono-Regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraMono-Regular.eot
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraMono-Regular.ttf
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraMono-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraMono-Regular.woff
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraSans-Bold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraSans-Bold.eot
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraSans-Bold.ttf
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraSans-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraSans-Bold.woff
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraSans-BoldItalic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraSans-BoldItalic.eot
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraSans-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraSans-BoldItalic.ttf
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraSans-BoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraSans-BoldItalic.woff
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraSans-Italic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraSans-Italic.eot
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraSans-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraSans-Italic.ttf
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraSans-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraSans-Italic.woff
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraSans-Regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraSans-Regular.eot
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraSans-Regular.ttf
--------------------------------------------------------------------------------
/docs/assets/fonts/FiraSans-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/fonts/FiraSans-Regular.woff
--------------------------------------------------------------------------------
/docs/assets/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/images/favicon.ico
--------------------------------------------------------------------------------
/docs/assets/vendor/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/vendor/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/docs/assets/vendor/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/vendor/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/docs/assets/vendor/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/vendor/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/docs/assets/vendor/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/docs/assets/vendor/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/docs/entities/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Entities
3 | ---
4 |
5 | The diaspora\* federation protocol currently knows the following entities:
6 |
7 | {% for entity in site.entities %}
8 | * [{{ entity.title }}]({{ site.baseurl }}{{ entity.url }})
9 | {% endfor %}
10 |
--------------------------------------------------------------------------------
/docs/federation/diaspora_scheme.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: diaspora:// URI scheme
3 | ---
4 |
5 | ## Server and software independent links
6 |
7 | A `diaspora://` URL is used if a user wants to link to another post. It doesn't
8 | contain a server hostname so it is independent of the senders server. And it
9 | isn't software specific, it is thought to be compatible with every software
10 | that is compatible with the protocol, so the receiving software can display
11 | it as software specific URL.
12 |
13 | The format is similar to the route used for [fetching][fetching], so if the
14 | receiving server doesn't know the linked entity yet, it can just be fetched.
15 |
16 | When the entity with that `guid` is already available locally, the recipient
17 | should validate that it's from `author` before linking to it.
18 |
19 | ### Format
20 |
21 | `diaspora://:author/:type/:guid`
22 |
23 | #### Parameters
24 |
25 | | Name | Description |
26 | | -------- | -------------------------------------------------------------------- |
27 | | `author` | The [diaspora\* ID][diaspora-id] of the author of the linked entity. |
28 | | `type` | The type of the linked entity in `snake_case`. |
29 | | `guid` | The [GUID][guid] of the linked entity. |
30 |
31 | #### Example
32 |
33 | `diaspora://alice@example.org/post/17faf230675101350d995254001bd39e`
34 |
35 | [fetching]: {{ site.baseurl }}/federation/fetching.html
36 | [diaspora-id]: {{ site.baseurl }}/federation/types.html#diaspora-id
37 | [guid]: {{ site.baseurl }}/federation/types.html#guid
38 |
--------------------------------------------------------------------------------
/docs/federation/encryption.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Encryption
3 | ---
4 |
5 | diaspora\* wraps the Salmon [Magic Envelope][magicsig] into a simple JSON structure, to encrypt private messages.
6 |
7 | ## Encrypted Magic Envelope
8 |
9 | ### JSON structure
10 |
11 | ~~~json
12 | {
13 | "aes_key": "...",
14 | "encrypted_magic_envelope": "..."
15 | }
16 | ~~~
17 |
18 | | Key | Description |
19 | | -------------------------- |------------------------------------------------------------------------------------------------------------------------ |
20 | | `aes_key` | The [AES Key JSON](#aes-key-json-structure) encrypted with the recipients public key using RSA and then base64 encoded. |
21 | | `encrypted_magic_envelope` | The [Magic Envelope][magicsig] encrypted with the `aes_key` using AES-256-CBC and then base64 encoded. |
22 |
23 | ### AES Key JSON structure
24 |
25 | ~~~json
26 | {
27 | "key": "...",
28 | "iv": "..."
29 | }
30 | ~~~
31 |
32 | | Key | Description |
33 | | ----- |---------------------------- |
34 | | `key` | The base64 encoded AES key. |
35 | | `iv` | The base64 encoded AES iv. |
36 |
37 | Both `key` and `iv` have to be suitable for AES-256-CBC.
38 |
39 | ## Additional information and specifications
40 |
41 | * [Magic Envelope][magicsig]
42 |
43 | [magicsig]: {{ site.baseurl }}/federation/magicsig.html#magic-envelope
44 |
--------------------------------------------------------------------------------
/docs/federation/xml_serialization.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: XML Serialization
3 | ---
4 |
5 | The [entities][entities] are serialized to XML, before they are added to the [Magic Envelope][magicsig].
6 |
7 | ## Root element
8 |
9 | The root element is named like the entity-name in `snake_case`.
10 |
11 | Examples: `status_message`, `comment`, `like`
12 |
13 | ## Properties
14 |
15 | The properties are added as child-elements, with the value string-serialized as described in [value formats][types] as
16 | content of the element.
17 |
18 | The order of the elements is not specified.
19 |
20 | Elements may be empty, if they have no value.
21 |
22 | Unknown elements must be ignored while parsing (except for signature-verification of [relayables][relayables]).
23 |
24 | ## Nested Entities
25 |
26 | Some entities have other entities as properties. The XML of the nested entity is nested into the root element of the
27 | parent entity. The same entity-type can be nested multiple times (e.g. `poll_answer` in `poll`).
28 |
29 | ## Example
30 |
31 | ~~~xml
32 |
33 | alice@example.org
34 | 17418fb029e6013487743131731751e9
35 | 2016-07-11T22:38:19Z
36 |
37 | I am a very interesting status update
38 | true
39 |
40 | ~~~
41 |
42 | [entities]: {{ site.baseurl }}/entities/
43 | [magicsig]: {{ site.baseurl }}/federation/magicsig.html
44 | [types]: {{ site.baseurl }}/federation/types.html
45 | [relayables]: {{ site.baseurl }}/federation/relayable.html
46 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | # diaspora\* federation protocol
5 |
6 | The purpose of this document is to specify the communications that go on between diaspora\* servers (and other servers
7 | supporting this protocol). If you experience any issues, feel free to [get in touch][communication] with us.
8 |
9 | ## Federation support
10 |
11 | This document specifies the future protocol for diaspora. diaspora\* release 0.6.3.0 and newer has support to receive
12 | [entities][entities] with this protocol, but still sends entities with an older protocol. Starting with diaspora\*
13 | release 0.7.0.0 this protocol is fully supported.
14 |
15 | ## Implementations
16 |
17 | An implementation of this protocol is available as a Ruby Gem under the AGPL [on Github][github]. This is the library used by the diaspora* project.
18 |
19 | The [Friendica][friendica] project also has [its implementation in PHP][phpimplementation].
20 |
21 | [communication]: https://wiki.diasporafoundation.org/How_we_communicate
22 | [entities]: {{ site.baseurl }}/entities/
23 | [github]: https://github.com/diaspora/diaspora_federation
24 | [friendica]: https://github.com/friendica/friendica
25 | [phpimplementation]: https://github.com/friendica/friendica/blob/develop/src/Protocol/Diaspora.php
26 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/callbacks.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | # Callbacks are used to communicate with the application. They are called to
5 | # fetch data and after data is received.
6 | class Callbacks
7 | # Initializes a new Callbacks object with the event-keys that need to be defined
8 | #
9 | # @example
10 | # Callbacks.new %i(
11 | # some_event
12 | # another_event
13 | # )
14 | #
15 | # @param [Hash] events event keys
16 | def initialize(events)
17 | @events = events
18 | @handlers = {}
19 | end
20 |
21 | # Defines a callback
22 | #
23 | # @example
24 | # callbacks.on :some_event do |arg1|
25 | # # do something
26 | # end
27 | #
28 | # @param [Symbol] event the event key
29 | # @param [Proc] callback the callback block
30 | # @raise [ArgumentError] if the event key is undefined or has already a handler
31 | def on(event, &callback)
32 | raise ArgumentError, "Undefined event #{event}" unless @events.include? event
33 | raise ArgumentError, "Already defined event #{event}" if @handlers.has_key? event
34 |
35 | @handlers[event] = callback
36 | end
37 |
38 | # Triggers a callback
39 | #
40 | # @example
41 | # callbacks.trigger :some_event, "foo"
42 | #
43 | # @param [Symbol] event the event key
44 | # @return [Object] the return-value of the callback
45 | # @raise [ArgumentError] if the event key is undefined
46 | def trigger(event, *args)
47 | raise ArgumentError, "Undefined event #{event}" unless @events.include? event
48 |
49 | @handlers[event].call(*args)
50 | end
51 |
52 | # Checks if all callbacks are defined
53 | # @return [Boolean]
54 | def definition_complete?
55 | missing_handlers.empty?
56 | end
57 |
58 | # Returns all undefined callbacks
59 | # @return [Hash] callback keys
60 | def missing_handlers
61 | @events - @handlers.keys
62 | end
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/discovery.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | # This module provides the namespace for the various classes implementing
5 | # WebFinger and other protocols used for metadata discovery on remote servers
6 | # in the diaspora* network.
7 | module Discovery
8 | end
9 | end
10 |
11 | require "diaspora_federation/discovery/exceptions"
12 | require "diaspora_federation/discovery/xrd_document"
13 | require "diaspora_federation/discovery/web_finger"
14 | require "diaspora_federation/discovery/h_card"
15 | require "diaspora_federation/discovery/discovery"
16 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/discovery/exceptions.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Discovery
5 | # Raised, if there is an error while discover a new person
6 | class DiscoveryError < RuntimeError
7 | end
8 |
9 | # Raised, if the XML structure is invalid
10 | class InvalidDocument < DiscoveryError
11 | end
12 |
13 | # Raised, if something is wrong with the webfinger data
14 | #
15 | # * if the +webfinger_url+ is missing or malformed in {HostMeta.from_base_url} or {HostMeta.from_xml}
16 | # * if the parsed XML from {WebFinger.from_xml} is incomplete
17 | # * if the html passed to {HCard.from_html} in some way is malformed, invalid or incomplete.
18 | class InvalidData < DiscoveryError
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/engine.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | # diaspora* federation rails engine
5 | class Engine < ::Rails::Engine
6 | isolate_namespace DiasporaFederation
7 |
8 | config.generators do |g|
9 | g.test_framework :rspec
10 | end
11 |
12 | config.after_initialize do
13 | DiasporaFederation.validate_config
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | # This namespace contains all the entities used to encapsulate data that is
5 | # passed around in the diaspora* network as part of the federation protocol.
6 | #
7 | # All entities must be defined in this namespace. Otherwise the XML
8 | # de-serialization will fail.
9 | module Entities
10 | end
11 | end
12 |
13 | require "diaspora_federation/entities/related_entity"
14 |
15 | # abstract types
16 | require "diaspora_federation/entities/post"
17 | require "diaspora_federation/entities/signable"
18 | require "diaspora_federation/entities/account_migration/signable"
19 | require "diaspora_federation/entities/relayable"
20 |
21 | # types
22 | require "diaspora_federation/entities/profile"
23 | require "diaspora_federation/entities/person"
24 | require "diaspora_federation/entities/contact"
25 | require "diaspora_federation/entities/account_deletion"
26 | require "diaspora_federation/entities/account_migration"
27 |
28 | require "diaspora_federation/entities/participation"
29 | require "diaspora_federation/entities/like"
30 | require "diaspora_federation/entities/comment"
31 | require "diaspora_federation/entities/poll_answer"
32 | require "diaspora_federation/entities/poll"
33 | require "diaspora_federation/entities/poll_participation"
34 |
35 | require "diaspora_federation/entities/embed"
36 | require "diaspora_federation/entities/location"
37 |
38 | require "diaspora_federation/entities/event"
39 | require "diaspora_federation/entities/event_participation"
40 |
41 | require "diaspora_federation/entities/photo"
42 | require "diaspora_federation/entities/status_message"
43 | require "diaspora_federation/entities/reshare"
44 |
45 | require "diaspora_federation/entities/message"
46 | require "diaspora_federation/entities/conversation"
47 |
48 | require "diaspora_federation/entities/retraction"
49 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/account_deletion.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity is sent when an account was deleted on a remote pod.
6 | #
7 | # @see Validators::AccountDeletionValidator
8 | class AccountDeletion < Entity
9 | # @!attribute [r] author
10 | # The diaspora* ID of the deleted account
11 | # @see Person#author
12 | # @return [String] diaspora* ID
13 | # @!attribute [r] diaspora_id
14 | # Alias for author
15 | # @see AccountDeletion#author
16 | # @return [String] diaspora* ID
17 | property :author, :string, alias: :diaspora_id
18 |
19 | # @return [String] string representation of this object
20 | def to_s
21 | "AccountDeletion:#{author}"
22 | end
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/account_migration/signable.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | class AccountMigration < Entity
6 | # AccountMigration::Signable is a module that encapsulates basic signature generation/verification flow for
7 | # AccountMigration entity.
8 | #
9 | # It is possible that implementation of diaspora* protocol requires to compute the signature for the
10 | # AccountMigration entity without instantiating the entity. In this case this module may be useful.
11 | module Signable
12 | include Entities::Signable
13 |
14 | # @return [String] string which is uniquely represents migration occasion
15 | def unique_migration_descriptor
16 | "AccountMigration:#{old_identity}:#{new_identity}"
17 | end
18 |
19 | # @see DiasporaFederation::Entities::Signable#signature_data
20 | def signature_data
21 | unique_migration_descriptor
22 | end
23 | end
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/comment.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity represents a comment to some kind of post (e.g. status message).
6 | #
7 | # @see Validators::CommentValidator
8 | class Comment < Entity
9 | # The {Comment} parent is a {Post}
10 | PARENT_TYPE = "Post"
11 |
12 | include Relayable
13 |
14 | # @!attribute [r] text
15 | # @return [String] the comment text
16 | property :text, :string
17 |
18 | # @!attribute [r] created_at
19 | # Comment entity creation time
20 | # @return [Time] creation time
21 | property :created_at, :timestamp, default: -> { Time.now.utc }
22 |
23 | # @!attribute [r] edited_at
24 | # The timestamp when the comment was edited
25 | # @return [Time] edited time
26 | property :edited_at, :timestamp, optional: true
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/contact.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity represents a contact with another person. A user issues it
6 | # when they start sharing/following with another user.
7 | #
8 | # @see Validators::ContactValidator
9 | class Contact < Entity
10 | # @!attribute [r] author
11 | # The diaspora* ID of the person who shares their profile
12 | # @see Person#author
13 | # @return [String] sender ID
14 | property :author, :string
15 |
16 | # @!attribute [r] recipient
17 | # The diaspora* ID of the person who will be shared with
18 | # @see Validation::Rule::DiasporaId
19 | # @return [String] recipient ID
20 | property :recipient, :string
21 |
22 | # @!attribute [r] following
23 | # @return [Boolean] if the author is following the person
24 | property :following, :boolean, default: true
25 |
26 | # @!attribute [r] sharing
27 | # @return [Boolean] if the author is sharing with the person
28 | property :sharing, :boolean, default: true
29 |
30 | # @!attribute [r] blocking
31 | # @return [Boolean] if the author is blocking the person
32 | property :blocking, :boolean, optional: true, default: false
33 |
34 | # @return [String] string representation of this object
35 | def to_s
36 | "Contact:#{author}:#{recipient}"
37 | end
38 |
39 | private
40 |
41 | def validate
42 | super
43 |
44 | return unless (following || sharing) && blocking
45 |
46 | raise ValidationError,
47 | "flags invalid: following:#{following}/sharing:#{sharing} and blocking:#{blocking} can't both be true"
48 | end
49 | end
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/conversation.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity represents a private conversation between users.
6 | #
7 | # @see Validators::ConversationValidator
8 | class Conversation < Entity
9 | # @!attribute [r] author
10 | # The diaspora* ID of the person initiated the conversation
11 | # @see Person#author
12 | # @return [String] diaspora* ID
13 | property :author, :string
14 |
15 | # @!attribute [r] guid
16 | # A random string of at least 16 chars
17 | # @see Validation::Rule::Guid
18 | # @return [String] conversation guid
19 | property :guid, :string
20 |
21 | # @!attribute [r] subject
22 | # @return [String] the conversation subject
23 | property :subject, :string
24 |
25 | # @!attribute [r] created_at
26 | # @return [Time] Conversation creation time
27 | property :created_at, :timestamp, default: -> { Time.now.utc }
28 |
29 | # @!attribute [r] participants
30 | # The diaspora* IDs of the persons participating the conversation separated by ";"
31 | # @return [String] participants diaspora* IDs
32 | property :participants, :string
33 |
34 | # @!attribute [r] messages
35 | # @return [[Entities::Message]] Messages of this conversation
36 | entity :messages, [Entities::Message], default: []
37 |
38 | private
39 |
40 | def validate
41 | super
42 | messages.each do |message|
43 | raise ValidationError, "nested #{message} has different author: author=#{author}" if message.author != author
44 | end
45 | end
46 | end
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/embed.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity is used to specify embed information about an URL that should be embedded.
6 | #
7 | # @see Validators::EmbedValidator
8 | class Embed < Entity
9 | # @!attribute [r] url
10 | # URL that should be embedded.
11 | # @return [String] url
12 | property :url, :string, optional: true
13 |
14 | # @!attribute [r] title
15 | # The title of the embedded URL.
16 | # @return [String] title
17 | property :title, :string, optional: true
18 |
19 | # @!attribute [r] description
20 | # The description of the embedded URL.
21 | # @return [String] description
22 | property :description, :string, optional: true
23 |
24 | # @!attribute [r] image
25 | # The image of the embedded URL.
26 | # @return [String] image
27 | property :image, :string, optional: true
28 |
29 | # @!attribute [r] nothing
30 | # True, if nothing should be embedded.
31 | # @return [String] nothing
32 | property :nothing, :boolean, optional: true
33 |
34 | # @return [String] string representation of this object
35 | def to_s
36 | "Embed#{":#{url}" if url}"
37 | end
38 |
39 | def validate
40 | super
41 |
42 | raise ValidationError, "Either 'url' must be set or 'nothing' must be 'true'" unless nothing ^ url
43 | end
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/event_participation.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity represents a participation in an event, i.e. it is issued when a user responds to en event.
6 | #
7 | # @see Validators::EventParticipationValidator
8 | class EventParticipation < Entity
9 | # The {EventParticipation} parent is an {Event}
10 | PARENT_TYPE = "Event"
11 |
12 | include Relayable
13 |
14 | # @!attribute [r] status
15 | # The participation status of the user
16 | # "accepted", "declined" or "tentative"
17 | # @return [String] event participation status
18 | property :status, :string
19 |
20 | # @!attribute [r] edited_at
21 | # The timestamp when the event participation was edited
22 | # @return [Time] edited time
23 | property :edited_at, :timestamp, optional: true
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/like.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity represents a like to some kind of post (e.g. status message).
6 | #
7 | # @see Validators::LikeValidator
8 | class Like < Entity
9 | include Relayable
10 |
11 | # @!attribute [r] parent_type
12 | # A string describing the type of the parent
13 | # Can be "Post" or "Comment" (Comments are currently not implemented in the
14 | # diaspora* frontend).
15 | # @return [String] parent type
16 | property :parent_type, :string
17 |
18 | # @!attribute [r] positive
19 | # If +true+ set a like, if +false+, set a dislike (dislikes are currently not
20 | # implemented in the diaspora* frontend).
21 | # @return [Boolean] is it a like or a dislike
22 | property :positive, :boolean
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/location.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity is used to specify location data and used embedded in a status message.
6 | #
7 | # @see Validators::LocationValidator
8 | class Location < Entity
9 | # @!attribute [r] address
10 | # A string describing your location, e.g. a city name, a street name, etc
11 | # @return [String] address
12 | property :address, :string
13 |
14 | # @!attribute [r] lat
15 | # Geographical latitude of your location
16 | # @return [String] latitude
17 | property :lat, :string
18 |
19 | # @!attribute [r] lng
20 | # Geographical longitude of your location
21 | # @return [String] longitude
22 | property :lng, :string
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/message.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity represents a private message exchanged in private conversation.
6 | #
7 | # @see Validators::MessageValidator
8 | class Message < Entity
9 | # @!attribute [r] author
10 | # The diaspora* ID of the author
11 | # @see Person#author
12 | # @return [String] diaspora* ID
13 | property :author, :string
14 |
15 | # @!attribute [r] guid
16 | # A random string of at least 16 chars
17 | # @see Validation::Rule::Guid
18 | # @return [String] guid
19 | property :guid, :string
20 |
21 | # @!attribute [r] text
22 | # Text of the message composed by a user
23 | # @return [String] text
24 | property :text, :string
25 |
26 | # @!attribute [r] created_at
27 | # Message creation time
28 | # @return [Time] creation time
29 | property :created_at, :timestamp, default: -> { Time.now.utc }
30 |
31 | # @!attribute [r] edited_at
32 | # The timestamp when the message was edited
33 | # @return [Time] edited time
34 | property :edited_at, :timestamp, optional: true
35 |
36 | # @!attribute [r] conversation_guid
37 | # Guid of a conversation this message belongs to
38 | # @see Conversation#guid
39 | # @return [String] conversation guid
40 | property :conversation_guid, :string
41 |
42 | # @return [String] string representation of this object
43 | def to_s
44 | "#{super}:#{conversation_guid}"
45 | end
46 | end
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/participation.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # Participation is sent to subscribe a user on updates for some post.
6 | #
7 | # @see Validators::Participation
8 | class Participation < Entity
9 | # @!attribute [r] author
10 | # The diaspora* ID of the author
11 | # @see Person#author
12 | # @return [String] diaspora* ID
13 | property :author, :string
14 |
15 | # @!attribute [r] guid
16 | # A random string of at least 16 chars
17 | # @see Validation::Rule::Guid
18 | # @return [String] guid
19 | property :guid, :string
20 |
21 | # @!attribute [r] parent_guid
22 | # @see StatusMessage#guid
23 | # @return [String] parent guid
24 | property :parent_guid, :string
25 |
26 | # @!attribute [r] parent_type
27 | # A string describing a type of the target to subscribe on
28 | # Currently only "Post" is supported.
29 | # @return [String] parent type
30 | property :parent_type, :string
31 |
32 | # @return [String] string representation of this object
33 | def to_s
34 | "#{super}:#{parent_type}:#{parent_guid}"
35 | end
36 |
37 | # Validates that the parent exists and the parent author is local
38 | def validate_parent
39 | parent = DiasporaFederation.callbacks.trigger(:fetch_related_entity, parent_type, parent_guid)
40 | raise ParentNotLocal, "obj=#{self}" unless parent&.local
41 | end
42 |
43 | # Validate that the parent is local.
44 | # @see Entity.from_hash
45 | # @param [Hash] hash entity initialization hash
46 | # @return [Entity] instance
47 | def self.from_hash(hash)
48 | super.tap(&:validate_parent)
49 | end
50 |
51 | # Raised, if the parent is not owned by the receiving pod.
52 | class ParentNotLocal < RuntimeError
53 | end
54 | end
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/person.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity contains the base data of a person.
6 | #
7 | # @see Validators::PersonValidator
8 | class Person < Entity
9 | # @!attribute [r] guid
10 | # This is just the guid. When a user creates an account on a pod, the pod
11 | # MUST assign them a guid - a random string of at least 16 chars.
12 | # @see Validation::Rule::Guid
13 | # @return [String] guid
14 | property :guid, :string
15 |
16 | # @!attribute [r] author
17 | # The diaspora* ID of the person
18 | # @see Validation::Rule::DiasporaId
19 | # @return [String] diaspora* ID
20 | # @!attribute [r] diaspora_id
21 | # alias for author
22 | # @see Person#author
23 | # @return [String] diaspora* ID
24 | property :author, :string, alias: :diaspora_id
25 |
26 | # @!attribute [r] url
27 | # @see Discovery::WebFinger#seed_url
28 | # @return [String] link to the pod
29 | property :url, :string
30 |
31 | # @!attribute [r] profile
32 | # All profile data of the person
33 | # @return [Profile] the profile of the person
34 | entity :profile, Entities::Profile
35 |
36 | # @!attribute [r] exported_key
37 | # @see Discovery::HCard#public_key
38 | # @return [String] public key
39 | property :exported_key, :string
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/poll.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity represents a poll and it is federated as an optional part of a status message.
6 | #
7 | # @see Validators::PollValidator
8 | class Poll < Entity
9 | # @!attribute [r] guid
10 | # A random string of at least 16 chars
11 | # @see Validation::Rule::Guid
12 | # @return [String] poll guid
13 | property :guid, :string
14 |
15 | # @!attribute [r] question
16 | # Text of the question posed by a user
17 | # @return [String] question
18 | property :question, :string
19 |
20 | # @!attribute [r] poll_answers
21 | # Array of possible answers for the poll
22 | # @return [[Entities::PollAnswer]] poll answers
23 | entity :poll_answers, [Entities::PollAnswer]
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/poll_answer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity represents a poll answer and is federated as a part of the Poll entity.
6 | #
7 | # @see Validators::PollAnswerValidator
8 | class PollAnswer < Entity
9 | # @!attribute [r] guid
10 | # A random string of at least 16 chars
11 | # @see Validation::Rule::Guid
12 | # @return [String] guid
13 | property :guid, :string
14 |
15 | # @!attribute [r] answer
16 | # Text of the answer
17 | # @return [String] answer
18 | property :answer, :string
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/poll_participation.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity represents a participation in poll, i.e. it is issued when a user votes for an answer in a poll.
6 | #
7 | # @see Validators::PollParticipationValidator
8 | class PollParticipation < Entity
9 | # The {PollParticipation} parent is a {Poll}
10 | PARENT_TYPE = "Poll"
11 |
12 | include Relayable
13 |
14 | # @!attribute [r] poll_answer_guid
15 | # Guid of the answer selected by the user
16 | # @see PollAnswer#guid
17 | # @return [String] poll answer guid
18 | property :poll_answer_guid, :string
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/post.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This is a module that defines common properties for a post which
6 | # include {StatusMessage} and {Reshare}.
7 | module Post
8 | # On inclusion of this module the required properties for a post are added to the object that includes it.
9 | #
10 | # @!attribute [r] author
11 | # The diaspora* ID of the person who posts the post
12 | # @see Person#author
13 | # @return [String] diaspora* ID
14 | #
15 | # @!attribute [r] guid
16 | # A random string of at least 16 chars
17 | # @see Validation::Rule::Guid
18 | # @return [String] status message guid
19 | #
20 | # @!attribute [r] created_at
21 | # Post entity creation time
22 | # @return [Time] creation time
23 | #
24 | # @!attribute [r] public
25 | # Shows whether the post is visible to everyone or only to some aspects
26 | # @return [Boolean] is it public
27 | #
28 | # @!attribute [r] provider_display_name
29 | # A string that describes a means by which a user has posted the post
30 | # @return [String] provider display name
31 | #
32 | # @param [Entity] entity the entity in which it is included
33 | def self.included(entity)
34 | entity.class_eval do
35 | property :author, :string
36 | property :guid, :string
37 | property :created_at, :timestamp, default: -> { Time.now.utc }
38 | property :public, :boolean, default: false
39 | property :provider_display_name, :string, optional: true
40 | end
41 | end
42 | end
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/entities/status_message.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Entities
5 | # This entity represents a status message sent by a user.
6 | #
7 | # @see Validators::StatusMessageValidator
8 | class StatusMessage < Entity
9 | include Post
10 |
11 | # @!attribute [r] text
12 | # Text of the status message composed by the user
13 | # @return [String] text of the status message
14 | property :text, :string
15 |
16 | # @!attribute [r] edited_at
17 | # The timestamp when the status message was edited
18 | # @return [Time] edited time
19 | property :edited_at, :timestamp, optional: true
20 |
21 | # @!attribute [r] photos
22 | # Optional photos attached to the status message
23 | # @return [[Entities::Photo]] photos
24 | entity :photos, [Entities::Photo], optional: true, default: []
25 |
26 | # @!attribute [r] location
27 | # Optional location attached to the status message
28 | # @return [Entities::Location] location
29 | entity :location, Entities::Location, optional: true
30 |
31 | # @!attribute [r] poll
32 | # Optional poll attached to the status message
33 | # @return [Entities::Poll] poll
34 | entity :poll, Entities::Poll, optional: true
35 |
36 | # @!attribute [r] event
37 | # Optional event attached to the status message
38 | # @return [Entities::Event] event
39 | entity :event, Entities::Event, optional: true
40 |
41 | # @!attribute [r] embed
42 | # Optional embed information of an URL that should be embedded in the status message
43 | # @return [Entities::Embed] embed
44 | entity :embed, Entities::Embed, optional: true
45 |
46 | private
47 |
48 | def validate
49 | super
50 | photos.each do |photo|
51 | if photo.author != author
52 | raise ValidationError, "nested #{photo} has different author: author=#{author} obj=#{self}"
53 | end
54 | end
55 | end
56 | end
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/federation.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | # This module contains the federation logic
5 | module Federation
6 | end
7 | end
8 |
9 | require "diaspora_federation/federation/diaspora_url_parser"
10 | require "diaspora_federation/federation/fetcher"
11 | require "diaspora_federation/federation/receiver"
12 | require "diaspora_federation/federation/sender"
13 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/federation/diaspora_url_parser.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Federation
5 | # This module is for parsing and fetching linked entities.
6 | module DiasporaUrlParser
7 | include Logging
8 |
9 | # Regex to find diaspora:// URLs
10 | DIASPORA_URL_REGEX = %r{
11 | (?:web\+)?diaspora://
12 | (#{Validation::Rule::DiasporaId::DIASPORA_ID_REGEX})/
13 | (#{Entity::ENTITY_NAME_REGEX})/
14 | (#{Validation::Rule::Guid::VALID_CHARS})
15 | }ux.freeze
16 |
17 | # Parses all diaspora:// URLs from the text and fetches the entities from
18 | # the remote server if needed.
19 | # @param [String] sender the diaspora* ID of the sender of the entity
20 | # @param [String] text text with diaspora:// URLs to fetch
21 | def self.fetch_linked_entities(text)
22 | text.scan(DIASPORA_URL_REGEX).each do |author, type, guid|
23 | fetch_entity(author, type, guid)
24 | end
25 | end
26 |
27 | private_class_method def self.fetch_entity(author, type, guid)
28 | class_name = Entity.entity_class(type).to_s.rpartition("::").last
29 | return if DiasporaFederation.callbacks.trigger(:fetch_related_entity, class_name, guid)
30 |
31 | Fetcher.fetch_public(author, type, guid)
32 | rescue => e # rubocop:disable Style/RescueStandardError
33 | logger.error "Failed to fetch linked entity #{type}:#{guid}: #{e.class}: #{e.message}"
34 | end
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/federation/receiver.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Federation
5 | # This module parses and receives entities.
6 | module Receiver
7 | extend Logging
8 |
9 | # Receive a public message
10 | # @param [String] data message to receive
11 | def self.receive_public(data)
12 | magic_env_xml = Nokogiri::XML(data).root
13 | magic_env = Salmon::MagicEnvelope.unenvelop(magic_env_xml)
14 | Public.new(magic_env).receive
15 | rescue => e # rubocop:disable Style/RescueStandardError
16 | logger.error "failed to receive public message: #{e.class}: #{e.message}"
17 | logger.debug "received data:\n#{data}"
18 | raise e
19 | end
20 |
21 | # Receive a private message
22 | # @param [String] data message to receive
23 | # @param [OpenSSL::PKey::RSA] recipient_private_key recipient private key to decrypt the message
24 | # @param [Object] recipient_id the identifier to persist the entity for the correct user,
25 | # see +receive_entity+ callback
26 | def self.receive_private(data, recipient_private_key, recipient_id)
27 | raise ArgumentError, "no recipient key provided" unless recipient_private_key.instance_of?(OpenSSL::PKey::RSA)
28 |
29 | magic_env_xml = Salmon::EncryptedMagicEnvelope.decrypt(data, recipient_private_key)
30 | magic_env = Salmon::MagicEnvelope.unenvelop(magic_env_xml)
31 | Private.new(magic_env, recipient_id).receive
32 | rescue => e # rubocop:disable Style/RescueStandardError
33 | logger.error "failed to receive private message for #{recipient_id}: #{e.class}: #{e.message}"
34 | logger.debug "received data:\n#{data}"
35 | raise e
36 | end
37 | end
38 | end
39 | end
40 |
41 | require "diaspora_federation/federation/receiver/exceptions"
42 | require "diaspora_federation/federation/receiver/abstract_receiver"
43 | require "diaspora_federation/federation/receiver/public"
44 | require "diaspora_federation/federation/receiver/private"
45 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/federation/receiver/abstract_receiver.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Federation
5 | module Receiver
6 | # Common functionality for receivers
7 | class AbstractReceiver
8 | include Logging
9 |
10 | # Creates a new receiver
11 | # @param [MagicEnvelope] magic_envelope the received magic envelope
12 | # @param [Object] recipient_id the identifier of the recipient of a private message
13 | def initialize(magic_envelope, recipient_id=nil)
14 | @entity = magic_envelope.payload
15 | @sender = magic_envelope.sender
16 | @recipient_id = recipient_id
17 | end
18 |
19 | # Validates and receives the entity
20 | def receive
21 | validate_and_receive
22 | rescue => e # rubocop:disable Style/RescueStandardError
23 | logger.error "failed to receive #{entity}"
24 | raise e
25 | end
26 |
27 | private
28 |
29 | attr_reader :entity, :sender, :recipient_id
30 |
31 | def validate_and_receive
32 | validate
33 | fetch_linked_entities_from_text
34 | DiasporaFederation.callbacks.trigger(:receive_entity, entity, sender, recipient_id)
35 | logger.info "successfully received #{entity} from person #{sender}#{" for #{recipient_id}" if recipient_id}"
36 | end
37 |
38 | def validate
39 | raise InvalidSender, "invalid sender: #{sender}" unless sender_valid?
40 | end
41 |
42 | def sender_valid?
43 | if entity.respond_to?(:sender_valid?)
44 | entity.sender_valid?(sender)
45 | else
46 | sender == entity.author
47 | end
48 | end
49 |
50 | def fetch_linked_entities_from_text
51 | DiasporaUrlParser.fetch_linked_entities(entity.text) if entity.respond_to?(:text) && entity.text
52 | end
53 | end
54 | end
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/federation/receiver/exceptions.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Federation
5 | module Receiver
6 | # Raised, if the sender of the {Salmon::MagicEnvelope} is not allowed to send the entity.
7 | class InvalidSender < RuntimeError
8 | end
9 |
10 | # Raised, if receiving a private message without recipient.
11 | class RecipientRequired < RuntimeError
12 | end
13 |
14 | # Raised, if receiving a message with public receiver which is not public but should be.
15 | class NotPublic < RuntimeError
16 | end
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/federation/receiver/private.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Federation
5 | module Receiver
6 | # Receiver for private entities
7 | class Private < AbstractReceiver
8 | private
9 |
10 | def validate
11 | raise RecipientRequired if recipient_id.nil?
12 |
13 | super
14 | end
15 | end
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/federation/receiver/public.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Federation
5 | module Receiver
6 | # Receiver for public entities
7 | class Public < AbstractReceiver
8 | private
9 |
10 | def validate
11 | super
12 | validate_public_flag
13 | end
14 |
15 | def validate_public_flag
16 | return if !entity.respond_to?(:public) || entity.public
17 |
18 | if entity.is_a?(Entities::Profile) &&
19 | %i[bio birthday gender location].all? {|prop| entity.public_send(prop).nil? }
20 | return
21 | end
22 |
23 | raise NotPublic, "received entity #{entity} should be public!"
24 | end
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/federation/sender.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Federation
5 | # Federation logic to send messages to other pods
6 | module Sender
7 | # Send a public message to all urls
8 | #
9 | # @param [String] sender_id sender diaspora-ID
10 | # @param [String] obj_str object string representation for logging (e.g. type@guid)
11 | # @param [Array] urls receive-urls from pods
12 | # @param [String] xml salmon-xml
13 | # @return [Array] url to retry
14 | def self.public(sender_id, obj_str, urls, xml)
15 | hydra = HydraWrapper.new(sender_id, obj_str)
16 | urls.each {|url| hydra.insert_magic_env_request(url, xml) }
17 | hydra.send
18 | end
19 |
20 | # Send a private message to receive-urls
21 | #
22 | # @param [String] sender_id sender diaspora-ID
23 | # @param [String] obj_str object string representation for logging (e.g. type@guid)
24 | # @param [Hash] targets Hash with receive-urls (key) of peoples with encrypted salmon-xml for them (value)
25 | # @return [Hash] targets to retry
26 | def self.private(sender_id, obj_str, targets)
27 | hydra = HydraWrapper.new(sender_id, obj_str)
28 | targets.each {|url, json| hydra.insert_enc_magic_env_request(url, json) }
29 | hydra.send.to_h {|url| [url, targets[url]] }
30 | end
31 | end
32 | end
33 | end
34 |
35 | require "diaspora_federation/federation/sender/hydra_wrapper"
36 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/http_client.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "faraday"
4 | require "faraday/follow_redirects"
5 |
6 | module DiasporaFederation
7 | # A wrapper for {https://github.com/lostisland/faraday Faraday}
8 | #
9 | # @see Discovery::Discovery
10 | # @see Federation::Fetcher
11 | class HttpClient
12 | # Perform a GET request
13 | #
14 | # @param [String] uri the URI
15 | # @return [Faraday::Response] the response
16 | def self.get(uri)
17 | connection.get(uri)
18 | end
19 |
20 | # Gets the Faraday connection
21 | #
22 | # @return [Faraday::Connection] the response
23 | def self.connection
24 | create_default_connection unless @connection
25 | @connection.dup
26 | end
27 |
28 | private_class_method def self.create_default_connection
29 | options = {
30 | request: {timeout: DiasporaFederation.http_timeout},
31 | ssl: {ca_file: DiasporaFederation.certificate_authorities}
32 | }
33 |
34 | @connection = Faraday::Connection.new(options) do |builder|
35 | builder.use Faraday::FollowRedirects::Middleware, limit: DiasporaFederation.http_redirect_limit
36 |
37 | builder.adapter Faraday.default_adapter
38 | end
39 |
40 | @connection.headers["User-Agent"] = DiasporaFederation.http_user_agent
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/logging.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | # Logging module for the diaspora* federation
5 | #
6 | # It uses the logging-gem if available.
7 | module Logging
8 | # Add +logger+ also as class method when included
9 | # @param [Class] klass the class into which the module is included
10 | def self.included(klass)
11 | klass.extend(self)
12 | end
13 |
14 | private
15 |
16 | # Get the logger for this class
17 | #
18 | # Use the logging-gem if available, else use a default logger.
19 | def logger
20 | @logger ||= if defined?(::Logging::Logger)
21 | # Use logging-gem if available
22 | ::Logging::Logger[self]
23 | elsif defined?(::Rails)
24 | # Use rails logger if running in rails and no logging-gem is available
25 | ::Rails.logger
26 | else
27 | # fallback logger
28 | @logger = Logger.new($stdout)
29 | @logger.level = Logger::INFO
30 | @logger
31 | end
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/parsers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | # This namespace contains parsers which are used to deserialize federation entities
5 | # objects from supported formats (XML, JSON) to objects of DiasporaFederation::Entity
6 | # classes
7 | module Parsers
8 | end
9 | end
10 |
11 | require "diaspora_federation/parsers/base_parser"
12 | require "diaspora_federation/parsers/json_parser"
13 | require "diaspora_federation/parsers/xml_parser"
14 | require "diaspora_federation/parsers/relayable_json_parser"
15 | require "diaspora_federation/parsers/relayable_xml_parser"
16 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/parsers/relayable_json_parser.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Parsers
5 | # This is a parser of JSON serialized object, that is normally used for parsing data of relayables.
6 | # Assumed format differs from the usual entity by additional "property_order" property which is used to
7 | # compute signatures deterministically.
8 | # Input JSON for this parser is expected to match "/definitions/relayable" subschema of the JSON schema at
9 | # https://diaspora.github.io/diaspora_federation/schemas/federation_entities.json.
10 | class RelayableJsonParser < JsonParser
11 | # @see JsonParser#parse
12 | # @see BaseParser#parse
13 | # @return [Array[2]] comprehensive data for an entity instantiation
14 | def parse(json_hash)
15 | super.push(json_hash["property_order"])
16 | end
17 |
18 | private
19 |
20 | def from_json_sanity_validation(json_hash)
21 | super
22 | return unless json_hash["property_order"].nil?
23 |
24 | raise DeserializationError, "Required property is missing in JSON object: property_order"
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/parsers/relayable_xml_parser.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Parsers
5 | # This is a parser of XML serialized object that is normally used for parsing data of relayables.
6 | # Explanations about the XML data format can be found
7 | # {https://diaspora.github.io/diaspora_federation/federation/xml_serialization.html here}.
8 | # Specific features of relayables are described
9 | # {https://diaspora.github.io/diaspora_federation/federation/relayable.html here}.
10 | #
11 | # @see https://diaspora.github.io/diaspora_federation/federation/xml_serialization.html XML Serialization
12 | # documentation
13 | # @see https://diaspora.github.io/diaspora_federation/federation/relayable.html Relayable documentation
14 | class RelayableXmlParser < XmlParser
15 | # @see XmlParser#parse
16 | # @see BaseParser#parse
17 | # @return [Array[2]] comprehensive data for an entity instantiation
18 | def parse(*args)
19 | hash = super[0]
20 | [hash, hash.keys]
21 | end
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/rails.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "diaspora_federation/engine"
4 |
5 | require "diaspora_federation"
6 |
7 | module DiasporaFederation
8 | # diaspora* federation rails engine
9 | module Rails
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/salmon.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | # This module contains a diaspora*-specific implementation of parts of the
5 | # {http://www.salmon-protocol.org/ Salmon Protocol}.
6 | module Salmon
7 | # XML namespace url
8 | XMLNS = "https://joindiaspora.com/protocol"
9 | end
10 | end
11 |
12 | require "base64"
13 |
14 | require "diaspora_federation/salmon/aes"
15 | require "diaspora_federation/salmon/exceptions"
16 | require "diaspora_federation/salmon/magic_envelope"
17 | require "diaspora_federation/salmon/encrypted_magic_envelope"
18 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/salmon/exceptions.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Salmon
5 | # Raised, if failed to fetch the public key of the sender of the received message
6 | class SenderKeyNotFound < RuntimeError
7 | end
8 |
9 | # Raised, if the Magic Envelope XML structure is malformed.
10 | class InvalidEnvelope < RuntimeError
11 | end
12 |
13 | # Raised, if the calculated signature doesn't match the one contained in the
14 | # Magic Envelope.
15 | class InvalidSignature < RuntimeError
16 | end
17 |
18 | # Raised, if the parsed Magic Envelope specifies an unhandled data type.
19 | class InvalidDataType < RuntimeError
20 | end
21 |
22 | # Raised, if the parsed Magic Envelope specifies an unhandled algorithm.
23 | class InvalidAlgorithm < RuntimeError
24 | end
25 |
26 | # Raised, if the parsed Magic Envelope specifies an unhandled encoding.
27 | class InvalidEncoding < RuntimeError
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/schemas.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "pathname"
4 | require "json"
5 |
6 | module DiasporaFederation
7 | # A helper class to access the JSON schema.
8 | module Schemas
9 | # federation_entities schema uri
10 | FEDERATION_ENTITIES_URI = "https://diaspora.github.io/diaspora_federation/schemas/federation_entities.json"
11 |
12 | # Parsed federation_entities schema
13 | def self.federation_entities
14 | @federation_entities ||= JSON.parse(
15 | Pathname.new(__dir__).join("schemas", "federation_entities.json").read
16 | )
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "fabrication"
4 |
5 | require "diaspora_federation"
6 | require "diaspora_federation/test/entity_generator"
7 |
8 | module DiasporaFederation
9 | # This module encapsulates helper functions maybe wanted by a testsuite of a diaspora_federation gem user application.
10 | module Test
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/test/entity_generator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Test
5 | # Generator to instantiate entities
6 | class EntityGenerator < Fabrication::Generator::Base
7 | def self.supports?(klass)
8 | klass.ancestors.include?(DiasporaFederation::Entity)
9 | end
10 |
11 | def build_instance
12 | self._instance = resolved_class.new(_attributes)
13 | end
14 |
15 | def to_hash(attributes=[], _callbacks=[])
16 | process_attributes(attributes)
17 | _attributes.transform_keys(&:to_sym)
18 | end
19 | end
20 |
21 | Fabrication.configure do |config|
22 | config.generators << EntityGenerator
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/account_deletion_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::AccountDeletion}.
6 | class AccountDeletionValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :author, :diaspora_id
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/account_migration_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::AccountMigration}.
6 | class AccountMigrationValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :author, :diaspora_id
10 |
11 | rule :profile, :not_nil
12 |
13 | rule :old_identity, :diaspora_id
14 |
15 | rule :remote_photo_path, URI: [:path]
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/comment_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Comment}.
6 | class CommentValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | include RelayableValidator
10 |
11 | rule :text, [:not_empty,
12 | length: {maximum: 65_535}]
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/contact_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Contact}.
6 | class ContactValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :author, :diaspora_id
10 | rule :recipient, :diaspora_id
11 | rule :following, :boolean
12 | rule :sharing, :boolean
13 | rule :blocking, :boolean
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/conversation_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Conversation}.
6 | class ConversationValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :author, :diaspora_id
10 | rule :guid, :guid
11 |
12 | rule :subject, [:not_empty, length: {maximum: 255}]
13 |
14 | rule :participants, [:not_empty, diaspora_id_list: {minimum: 2}]
15 | rule :messages, :not_nil
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/embed_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Embed}.
6 | class EmbedValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :url, :URI
10 | rule :title, length: {maximum: 255}
11 | rule :description, length: {maximum: 65_535}
12 | rule :image, URI: %i[host path]
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/event_participation_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::EventParticipation}.
6 | class EventParticipationValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | include RelayableValidator
10 |
11 | rule :status, [:not_empty, regular_expression: {regex: /\A(accepted|declined|tentative)\z/}]
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/event_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Event}.
6 | class EventValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :author, :diaspora_id
10 |
11 | rule :guid, :guid
12 |
13 | rule :summary, [:not_empty, length: {maximum: 255}]
14 | rule :description, length: {maximum: 65_535}
15 |
16 | rule :start, :not_nil
17 |
18 | rule :all_day, :boolean
19 |
20 | rule :timezone, regular_expression: {regex: %r{\A[A-Za-z_-]{,14}(/[A-Za-z_-]{,14}){1,2}\z}}
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/h_card_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Discovery::HCard}.
6 | #
7 | # @note
8 | class HCardValidator < OptionalAwareValidator
9 | include Validation
10 |
11 | rule :guid, :guid
12 |
13 | # The name must not contain a semicolon because of mentions.
14 | # @{ ; }
15 | rule :full_name, regular_expression: {regex: /\A[^;]{,70}\z/}
16 | rule :first_name, regular_expression: {regex: /\A[^;]{,32}\z/}
17 | rule :last_name, regular_expression: {regex: /\A[^;]{,32}\z/}
18 |
19 | # this urls can be relative
20 | rule :photo_large_url, [:not_nil, URI: [:path]]
21 | rule :photo_medium_url, [:not_nil, URI: [:path]]
22 | rule :photo_small_url, [:not_nil, URI: [:path]]
23 |
24 | rule :public_key, :public_key
25 |
26 | rule :searchable, :boolean
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/like_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Like}.
6 | class LikeValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | include RelayableValidator
10 |
11 | rule :parent_type, [:not_empty, regular_expression: {regex: /\A(Post|Comment)\z/}]
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/location_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Location}.
6 | class LocationValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :lat, :not_empty
10 | rule :lng, :not_empty
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/message_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Message}.
6 | class MessageValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :author, :diaspora_id
10 | rule :guid, :guid
11 | rule :conversation_guid, :guid
12 |
13 | rule :text, [:not_empty,
14 | length: {maximum: 65_535}]
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/optional_aware_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # Abstract validator which only validates optional fields when they are not nil.
6 | class OptionalAwareValidator < Validation::Validator
7 | def rules
8 | super.reject do |field, rules|
9 | @obj.public_send(field).nil? &&
10 | !rules.map(&:class).include?(Validation::Rule::NotNil) &&
11 | optional_props.include?(field)
12 | end
13 | end
14 |
15 | private
16 |
17 | def optional_props
18 | return [] unless @obj.class.respond_to?(:optional_props)
19 |
20 | @obj.class.optional_props
21 | end
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/participation_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Participation}.
6 | class ParticipationValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :author, :diaspora_id
10 | rule :guid, :guid
11 | rule :parent_guid, :guid
12 | rule :parent_type, [:not_empty, regular_expression: {regex: /\APost\z/}]
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/person_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Person}.
6 | class PersonValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :guid, :guid
10 |
11 | rule :author, :diaspora_id
12 |
13 | rule :url, %i[not_nil URI]
14 |
15 | rule :profile, :not_nil
16 |
17 | rule :exported_key, :public_key
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/photo_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Photo}.
6 | class PhotoValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :guid, :guid
10 |
11 | rule :author, :diaspora_id
12 |
13 | rule :public, :boolean
14 |
15 | rule :remote_photo_path, [:not_empty, URI: [:path]]
16 |
17 | rule :remote_photo_name, :not_empty
18 |
19 | rule :status_message_guid, :guid
20 |
21 | rule :text, length: {maximum: 65_535}
22 |
23 | rule :height, :numeric
24 |
25 | rule :width, :numeric
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/poll_answer_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::PollAnswer}.
6 | class PollAnswerValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :guid, :guid
10 | rule :answer, [:not_empty, length: {maximum: 255}]
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/poll_participation_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::PollParticipation}.
6 | class PollParticipationValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | include RelayableValidator
10 |
11 | rule :poll_answer_guid, :guid
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/poll_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Poll}.
6 | class PollValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :guid, :guid
10 | rule :question, [:not_empty, length: {maximum: 255}]
11 | rule :poll_answers, length: {minimum: 2}
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/profile_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Profile}.
6 | class ProfileValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :author, :diaspora_id
10 |
11 | # The name must not contain a semicolon because of mentions.
12 | # @{ ; }
13 | rule :full_name, regular_expression: {regex: /\A[^;]{,70}\z/}
14 | rule :first_name, regular_expression: {regex: /\A[^;]{,32}\z/}
15 | rule :last_name, regular_expression: {regex: /\A[^;]{,32}\z/}
16 |
17 | # These urls can be relative.
18 | rule :image_url, URI: [:path]
19 | rule :image_url_medium, URI: [:path]
20 | rule :image_url_small, URI: [:path]
21 |
22 | rule :birthday, :birthday
23 |
24 | rule :gender, length: {maximum: 255}
25 | rule :bio, length: {maximum: 65_535}
26 | rule :location, length: {maximum: 255}
27 |
28 | rule :searchable, :boolean
29 | rule :public, :boolean
30 | rule :nsfw, :boolean
31 |
32 | rule :tag_string, tag_count: {maximum: 5}
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/related_entity_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::RelatedEntity}.
6 | class RelatedEntityValidator < Validation::Validator
7 | include Validation
8 |
9 | rule :author, :diaspora_id
10 | rule :local, :boolean
11 | rule :public, :boolean
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/relayable_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This is included to validatros which validate entities which include {Entities::Relayable}.
6 | module RelayableValidator
7 | # When this module is included in a Validator child it adds rules for relayable validation.
8 | # @param [Validation::Validator] validator the validator in which it is included
9 | def self.included(validator)
10 | validator.class_eval do
11 | rule :author, :diaspora_id
12 | rule :guid, :guid
13 | rule :parent_guid, :guid
14 | rule :parent, :not_nil
15 | end
16 | end
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/reshare_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Reshare}.
6 | class ReshareValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :root_author, :diaspora_id
10 |
11 | rule :root_guid, :guid
12 |
13 | rule :author, :diaspora_id
14 |
15 | rule :guid, :guid
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/retraction_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::Retraction}.
6 | class RetractionValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :author, :diaspora_id
10 |
11 | rule :target_guid, :guid
12 | rule :target_type, :not_empty
13 | rule :target, :not_nil
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/rules/birthday.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "date"
4 |
5 | module Validation
6 | module Rule
7 | # Birthday validation rule
8 | #
9 | # Valid is:
10 | # * nil or an empty +String+
11 | # * a +Date+ object
12 | # * a +String+ with the format "yyyy-mm-dd" and is a valid +Date+, example: 2015-07-25
13 | class Birthday
14 | # The error key for this rule
15 | # @return [Symbol] error key
16 | def error_key
17 | :birthday
18 | end
19 |
20 | # Determines if value is a valid birthday date.
21 | def valid_value?(value)
22 | return true if value.nil? || (value.is_a?(String) && value.empty?)
23 | return true if value.is_a? Date
24 |
25 | if value.is_a?(String) && value.match?(/[0-9]{4}-[0-9]{2}-[0-9]{2}/)
26 | date_field = value.split("-").map(&:to_i)
27 | return Date.valid_civil?(date_field[0], date_field[1], date_field[2])
28 | end
29 |
30 | false
31 | end
32 |
33 | # This rule has no params.
34 | # @return [Hash] params
35 | def params
36 | {}
37 | end
38 | end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/rules/boolean.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Validation
4 | module Rule
5 | # Boolean validation rule
6 | #
7 | # Valid is:
8 | # * a +String+: "true", "false", "t", "f", "yes", "no", "y", "n", "1", "0"
9 | # * a +Integer+: 1 or 0
10 | # * a +Boolean+: true or false
11 | class Boolean
12 | # The error key for this rule
13 | # @return [Symbol] error key
14 | def error_key
15 | :boolean
16 | end
17 |
18 | # Determines if value is a valid +boolean+
19 | def valid_value?(value)
20 | return false if value.nil?
21 |
22 | case value
23 | when String
24 | true if value =~ /\A(true|false|t|f|yes|no|y|n|1|0)\z/i
25 | when Integer
26 | true if [1, 0].include?(value)
27 | else
28 | [true, false].include?(value)
29 | end
30 | end
31 |
32 | # This rule has no params.
33 | # @return [Hash] params
34 | def params
35 | {}
36 | end
37 | end
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/rules/diaspora_id.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Validation
4 | module Rule
5 | # diaspora* ID validation rule
6 | #
7 | # A simple rule to validate the base structure of diaspora* IDs.
8 | class DiasporaId
9 | # Maximum length of a full diaspora* ID
10 | DIASPORA_ID_MAX_LENGTH = 255
11 |
12 | # The Regex for a valid diaspora* ID
13 | DIASPORA_ID_REGEX = begin
14 | username = "[[:lower:]\\d\\-\\.\\_]+"
15 | hostname_part = "[[:lower:]\\d\\-]"
16 | hostname = "#{hostname_part}+(?:[.]#{hostname_part}*)*"
17 | ipv4 = "(?:[\\d]{1,3}\\.){3}[\\d]{1,3}"
18 | ipv6 = "\\[(?:[[:xdigit:]]{0,4}:){0,7}[[:xdigit:]]{1,4}\\]"
19 | ip_addr = "(?:#{ipv4}|#{ipv6})"
20 | domain = "(?:#{hostname}|#{ip_addr})"
21 | port = "(?::[\\d]+)?"
22 |
23 | "#{username}\\@#{domain}#{port}"
24 | end
25 |
26 | # The Regex for validating a full diaspora* ID
27 | DIASPORA_ID = /\A#{DIASPORA_ID_REGEX}\z/u.freeze
28 |
29 | # The error key for this rule
30 | # @return [Symbol] error key
31 | def error_key
32 | :diaspora_id
33 | end
34 |
35 | # Determines if value is a valid diaspora* ID
36 | def valid_value?(value)
37 | return false unless value.is_a?(String)
38 | return false if value.length > DIASPORA_ID_MAX_LENGTH
39 |
40 | value =~ DIASPORA_ID
41 | end
42 |
43 | # This rule has no params.
44 | # @return [Hash] params
45 | def params
46 | {}
47 | end
48 | end
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/rules/diaspora_id_list.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Validation
4 | module Rule
5 | # Rule for validating the number of diaspora* IDs in a string.
6 | # The evaluated string is split at ";".
7 | class DiasporaIdList
8 | # This rule can have a +minimum+ or +maximum+ param.
9 | # @return [Hash] params
10 | attr_reader :params
11 |
12 | # Creates a new rule for a diaspora* ID list validation
13 | # @param [Hash] params
14 | # @option params [Integer] :minimum minimum allowed id count
15 | # @option params [Integer] :maximum maximum allowed id count
16 | def initialize(params={})
17 | %i[minimum maximum].each do |param|
18 | if params.include?(param) && !params[param].is_a?(Integer)
19 | raise ArgumentError, "The :#{param} needs to be an Integer"
20 | end
21 | end
22 |
23 | @params = params
24 | end
25 |
26 | # The error key for this rule
27 | # @return [Symbol] error key
28 | def error_key
29 | :diaspora_id_list
30 | end
31 |
32 | def valid_value?(value)
33 | ids = value.split(";")
34 | return false if params.include?(:maximum) && ids.count > params[:maximum]
35 | return false if params.include?(:minimum) && ids.count < params[:minimum]
36 |
37 | ids.each do |id|
38 | return false if DiasporaId::DIASPORA_ID.match(id).nil?
39 | end
40 | true
41 | end
42 | end
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/rules/guid.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Validation
4 | module Rule
5 | # GUID validation rule
6 | #
7 | # Valid is a +String+ that is at least 16 and at most 255 chars long. It contains only:
8 | # * Letters: a-z
9 | # * Numbers: 0-9
10 | # * Special chars: '-', '_', '@', '.' and ':'
11 | # Special chars aren't allowed at the end.
12 | class Guid
13 | # Allowed chars to validate a GUID with a regex
14 | VALID_CHARS = "[0-9A-Za-z\\-_@.:]{15,254}[0-9A-Za-z]"
15 |
16 | # The error key for this rule
17 | # @return [Symbol] error key
18 | def error_key
19 | :guid
20 | end
21 |
22 | # Determines if value is a valid +GUID+
23 | def valid_value?(value)
24 | value.is_a?(String) && value =~ /\A#{VALID_CHARS}\z/
25 | end
26 |
27 | # This rule has no params.
28 | # @return [Hash] params
29 | def params
30 | {}
31 | end
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/rules/not_nil.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Validation
4 | module Rule
5 | # Validates that a property is not +nil+
6 | class NotNil
7 | # The error key for this rule
8 | # @return [Symbol] error key
9 | def error_key
10 | :not_nil
11 | end
12 |
13 | # Determines if value is not nil
14 | def valid_value?(value)
15 | !value.nil?
16 | end
17 |
18 | # This rule has no params.
19 | # @return [Hash] params
20 | def params
21 | {}
22 | end
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/rules/public_key.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Validation
4 | module Rule
5 | # Public key validation rule
6 | #
7 | # A valid key must:
8 | # * start with "-----BEGIN PUBLIC KEY-----" and end with "-----END PUBLIC KEY-----"
9 | # or
10 | # * start with "-----BEGIN RSA PUBLIC KEY-----" and end with "-----END RSA PUBLIC KEY-----"
11 | class PublicKey
12 | # The error key for this rule
13 | # @return [Symbol] error key
14 | def error_key
15 | :public_key
16 | end
17 |
18 | # Determines if value is a valid public key
19 | def valid_value?(value)
20 | !value.nil? && (
21 | (value.strip.start_with?("-----BEGIN PUBLIC KEY-----") &&
22 | value.strip.end_with?("-----END PUBLIC KEY-----")) ||
23 | (value.strip.start_with?("-----BEGIN RSA PUBLIC KEY-----") &&
24 | value.strip.end_with?("-----END RSA PUBLIC KEY-----"))
25 | )
26 | end
27 |
28 | # This rule has no params.
29 | # @return [Hash] params
30 | def params
31 | {}
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/rules/tag_count.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Validation
4 | module Rule
5 | # Rule for validating the number of tags in a string.
6 | # Only the "#" characters will be counted.
7 | # The string can be nil.
8 | class TagCount
9 | # This rule must have a +maximum+ param.
10 | # @return [Hash] params
11 | attr_reader :params
12 |
13 | # Creates a new rule for a maximum tag count validation
14 | # @param [Hash] params
15 | # @option params [Integer] :maximum maximum allowed tag count
16 | def initialize(params)
17 | unless params.include?(:maximum) && params[:maximum].is_a?(Integer)
18 | raise ArgumentError, "A number has to be specified for :maximum"
19 | end
20 |
21 | @params = params
22 | end
23 |
24 | # The error key for this rule
25 | # @return [Symbol] error key
26 | def error_key
27 | :tag_count
28 | end
29 |
30 | # Determines if value doesn't have more than +maximum+ tags
31 | def valid_value?(value)
32 | value.nil? || value.count("#") <= params[:maximum]
33 | end
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/status_message_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Entities::StatusMessage}.
6 | class StatusMessageValidator < OptionalAwareValidator
7 | include Validation
8 |
9 | rule :author, :diaspora_id
10 |
11 | rule :guid, :guid
12 |
13 | rule :text, length: {maximum: 65_535}
14 |
15 | rule :photos, :not_nil
16 |
17 | rule :public, :boolean
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/validators/web_finger_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | module Validators
5 | # This validates a {Discovery::WebFinger}.
6 | #
7 | # @note It does not validate the guid and public key, because it will be
8 | # removed in the webfinger.
9 | class WebFingerValidator < OptionalAwareValidator
10 | include Validation
11 |
12 | rule :acct_uri, :not_empty
13 |
14 | rule :hcard_url, [:not_nil, URI: %i[host path]]
15 | rule :seed_url, %i[not_nil URI]
16 | rule :profile_url, URI: %i[host path]
17 | rule :atom_url, URI: %i[host path]
18 | rule :salmon_url, URI: %i[host path]
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/lib/diaspora_federation/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | # the gem version
5 | VERSION = "1.1.0"
6 | end
7 |
--------------------------------------------------------------------------------
/lib/tasks/build.rake:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | desc "Build gem into the pkg directory"
4 | task build: :test do
5 | FileUtils.rm_rf("pkg")
6 | Dir["*.gemspec"].each do |gemspec|
7 | system "gem build #{gemspec}"
8 | end
9 | FileUtils.mkdir_p("pkg")
10 | FileUtils.mv(Dir["*.gem"], "pkg")
11 |
12 | Rake::Task["update_json_schemas"].invoke
13 | end
14 |
15 | desc "Update JSON schemas for github-pages"
16 | task :update_json_schemas do
17 | git_clean = `git status --porcelain`.empty?
18 | sh "git stash" unless git_clean
19 |
20 | FileUtils.mkdir_p("docs/schemas")
21 | FileUtils.cp(Dir["lib/diaspora_federation/schemas/*.json"], "docs/schemas")
22 |
23 | sh "git add docs/schemas && git diff --staged --quiet || git commit -m 'Update JSON schemas for github-pages'"
24 | sh "git stash pop" unless git_clean
25 | end
26 |
27 | desc "Tags version, pushes to remote, and pushes gem"
28 | task release: :build do
29 | Dir["pkg/diaspora_federation-*-*.gem"].each do |gem|
30 | sh "gem push #{gem}"
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/spec/controllers/diaspora_federation/application_controller_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe ApplicationController, type: :controller do
5 | controller do
6 | def index
7 | head :ok
8 | end
9 | end
10 |
11 | describe "#set_locale" do
12 | it "sets the default locale" do
13 | expect(I18n).to receive(:locale=).with(:en)
14 | get :index
15 | end
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/controllers/diaspora_federation/h_card_controller_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe HCardController, type: :controller do
5 | routes { DiasporaFederation::Engine.routes }
6 |
7 | describe "GET #hcard" do
8 | it "succeeds when the person exists" do
9 | get :hcard, params: {guid: alice.guid}
10 | expect(response).to be_successful
11 | end
12 |
13 | it "contains the guid" do
14 | get :hcard, params: {guid: alice.guid}
15 | expect(response.body).to include "#{alice.guid}"
16 | end
17 |
18 | it "contains the username" do
19 | get :hcard, params: {guid: alice.guid}
20 | expect(response.body).to include "alice"
21 | end
22 |
23 | it "404s when the person does not exist" do
24 | get :hcard, params: {guid: "unknown_guid"}
25 | expect(response).to be_not_found
26 | end
27 |
28 | it "calls the fetch_person_for_hcard callback" do
29 | expect_callback(:fetch_person_for_hcard, alice.guid).and_call_original
30 |
31 | get :hcard, params: {guid: alice.guid}
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/spec/controllers/diaspora_federation/receive_controller_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe ReceiveController, type: :controller do
5 | routes { DiasporaFederation::Engine.routes }
6 |
7 | describe "POST #public" do
8 | context "magic envelope" do
9 | before do
10 | Mime::Type.register("application/magic-envelope+xml", :magic_envelope)
11 | @request.env["CONTENT_TYPE"] = "application/magic-envelope+xml"
12 | end
13 |
14 | it "returns a 202 if queued correctly" do
15 | expect_callback(:queue_public_receive, "")
16 |
17 | post :public, body: +""
18 | expect(response.code).to eq("202")
19 | end
20 | end
21 | end
22 |
23 | describe "POST #private" do
24 | context "encrypted magic envelope" do
25 | before do
26 | @request.env["CONTENT_TYPE"] = "application/json"
27 | end
28 |
29 | it "return a 404 if not queued successfully (unknown user guid)" do
30 | expect_callback(
31 | :queue_private_receive, "any-guid", "{\"aes_key\": \"key\", \"encrypted_magic_envelope\": \"env\"}"
32 | ).and_return(false)
33 |
34 | post :private,
35 | body: +"{\"aes_key\": \"key\", \"encrypted_magic_envelope\": \"env\"}",
36 | params: {guid: "any-guid"}
37 | expect(response.code).to eq("404")
38 | end
39 |
40 | it "returns a 202 if the callback returned true" do
41 | expect_callback(
42 | :queue_private_receive, "any-guid", "{\"aes_key\": \"key\", \"encrypted_magic_envelope\": \"env\"}"
43 | ).and_return(true)
44 |
45 | post :private,
46 | body: +"{\"aes_key\": \"key\", \"encrypted_magic_envelope\": \"env\"}",
47 | params: {guid: "any-guid"}
48 | expect(response.code).to eq("202")
49 | end
50 | end
51 | end
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/spec/factories.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "diaspora_federation/test/factories"
4 |
5 | Fabricator(:person) do
6 | diaspora_id { Fabricate.sequence(:diaspora_id) }
7 | url "http://somehost:3000/"
8 | serialized_public_key { Fabricate.sequence(:public_key) }
9 | end
10 |
11 | Fabricator(:user, class_name: Person) do
12 | diaspora_id { Fabricate.sequence(:diaspora_id) }
13 | url "http://localhost:3000/"
14 | after_build do |user|
15 | private_key = OpenSSL::PKey::RSA.generate(1024)
16 | user.serialized_private_key = private_key.export
17 | user.serialized_public_key = private_key.public_key.export
18 | end
19 | end
20 |
21 | Fabricator(:post, class_name: Entity) do
22 | initialize_with { resolved_class.new("Post") }
23 | author { Fabricate(:person) }
24 | end
25 |
26 | Fabricator(:comment, class_name: Entity) do
27 | initialize_with { resolved_class.new("Comment") }
28 | author { Fabricate(:person) }
29 | end
30 |
31 | Fabricator(:poll, class_name: Entity) do
32 | initialize_with { resolved_class.new("Poll") }
33 | author { Fabricate(:person) }
34 | end
35 |
36 | Fabricator(:event, class_name: Entity) do
37 | initialize_with { resolved_class.new("Event") }
38 | author { Fabricate(:person) }
39 | end
40 |
41 | Fabricator(:conversation, class_name: Entity) do
42 | initialize_with { resolved_class.new("Conversation") }
43 | author { Fabricate(:person) }
44 | end
45 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/account_deletion_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::AccountDeletion do
5 | let(:data) { Fabricate.attributes_for(:account_deletion_entity) }
6 |
7 | let(:xml) { <<~XML }
8 |
9 | #{data[:author]}
10 |
11 | XML
12 |
13 | let(:string) { "AccountDeletion:#{data[:author]}" }
14 |
15 | it_behaves_like "an Entity subclass"
16 |
17 | it_behaves_like "an XML Entity"
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/account_migration/signable_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::AccountMigration::Signable do
5 | let(:entity) { TestAMSignableEntity.new({}) }
6 |
7 | class TestAMSignableEntity < Entity
8 | include Entities::AccountMigration::Signable
9 |
10 | property :my_signature, :string, default: nil
11 |
12 | def old_identity
13 | "old"
14 | end
15 |
16 | def new_identity
17 | "new"
18 | end
19 | end
20 |
21 | it_behaves_like "a signable" do
22 | let(:test_class) { TestAMSignableEntity }
23 | let(:test_string) { "AccountMigration:old:new" }
24 | end
25 |
26 | describe "#unique_migration_descriptor" do
27 | it "composes a string using #old_identity and #new_identity" do
28 | expect(entity.unique_migration_descriptor).to eq("AccountMigration:old:new")
29 | end
30 | end
31 |
32 | describe "#signature_data" do
33 | it "delegates to #unique_migration_descriptor" do
34 | expect(entity.signature_data).to eq("AccountMigration:old:new")
35 | end
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/comment_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::Comment do
5 | let(:parent) { Fabricate(:post, author: bob) }
6 | let(:parent_entity) { Fabricate(:related_entity, author: bob.diaspora_id) }
7 | let(:data) {
8 | Fabricate
9 | .attributes_for(
10 | :comment_entity,
11 | author: alice.diaspora_id,
12 | parent_guid: parent.guid,
13 | parent: parent_entity
14 | ).tap {|hash| add_signatures(hash) }
15 | }
16 |
17 | let(:xml) { <<~XML }
18 |
19 | #{data[:author]}
20 | #{data[:guid]}
21 | #{parent.guid}
22 | #{data[:text]}
23 | #{data[:created_at].utc.iso8601}
24 | #{data[:edited_at].utc.iso8601}
25 | #{data[:author_signature]}
26 |
27 | XML
28 |
29 | let(:json) { <<~JSON }
30 | {
31 | "entity_type": "comment",
32 | "entity_data": {
33 | "author": "#{data[:author]}",
34 | "guid": "#{data[:guid]}",
35 | "parent_guid": "#{parent.guid}",
36 | "author_signature": "#{data[:author_signature]}",
37 | "text": "#{data[:text]}",
38 | "created_at": "#{data[:created_at].iso8601}",
39 | "edited_at": "#{data[:edited_at].iso8601}"
40 | },
41 | "property_order": [
42 | "author",
43 | "guid",
44 | "parent_guid",
45 | "text",
46 | "created_at",
47 | "edited_at"
48 | ]
49 | }
50 | JSON
51 |
52 | let(:string) { "Comment:#{data[:guid]}:#{parent.guid}" }
53 |
54 | it_behaves_like "an Entity subclass"
55 |
56 | it_behaves_like "an XML Entity", [:created_at]
57 |
58 | it_behaves_like "a JSON Entity"
59 |
60 | it_behaves_like "a relayable Entity"
61 |
62 | it_behaves_like "a relayable JSON entity"
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/contact_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::Contact do
5 | let(:data) { Fabricate.attributes_for(:contact_entity) }
6 |
7 | let(:xml) { <<~XML }
8 |
9 | #{data[:author]}
10 | #{data[:recipient]}
11 | #{data[:following]}
12 | #{data[:sharing]}
13 | #{data[:blocking]}
14 |
15 | XML
16 |
17 | let(:string) { "Contact:#{data[:author]}:#{data[:recipient]}" }
18 |
19 | it_behaves_like "an Entity subclass"
20 |
21 | it_behaves_like "an XML Entity"
22 |
23 | describe "#validate" do
24 | it "allows 'following' and 'sharing' to be true" do
25 | combinations = [
26 | {following: true, sharing: true, blocking: false},
27 | {following: true, sharing: false, blocking: false},
28 | {following: false, sharing: true, blocking: false}
29 | ]
30 | combinations.each do |combination|
31 | expect { Entities::Contact.new(data.merge(combination)) }.not_to raise_error
32 | end
33 | end
34 |
35 | it "allows 'blocking' to be true" do
36 | expect {
37 | Entities::Contact.new(data.merge(following: false, sharing: false, blocking: true))
38 | }.not_to raise_error
39 | end
40 |
41 | it "doesn't allow 'following'/'sharing' and 'blocking' to be true" do
42 | combinations = [
43 | {following: true, sharing: true, blocking: true},
44 | {following: true, sharing: false, blocking: true},
45 | {following: false, sharing: true, blocking: true}
46 | ]
47 | combinations.each do |combination|
48 | expect { Entities::Contact.new(data.merge(combination)) }.to raise_error Entity::ValidationError
49 | end
50 | end
51 | end
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/embed_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::Embed do
5 | let(:data) { Fabricate.attributes_for(:embed_entity) }
6 |
7 | let(:xml) { <<~XML }
8 |
14 | XML
15 |
16 | let(:json) { <<~JSON }
17 | {
18 | "entity_type": "embed",
19 | "entity_data": {
20 | "url": "#{data[:url]}",
21 | "title": "#{data[:title]}",
22 | "description": "#{data[:description]}",
23 | "image": "#{data[:image]}"
24 | }
25 | }
26 | JSON
27 |
28 | let(:string) { "Embed:#{data[:url]}" }
29 |
30 | it_behaves_like "an Entity subclass"
31 |
32 | it_behaves_like "an XML Entity"
33 |
34 | it_behaves_like "a JSON Entity"
35 |
36 | describe "#validate" do
37 | it "allows 'url' to be set if 'nothing' is not true" do
38 | expect { Entities::Embed.new(data) }.not_to raise_error
39 | end
40 |
41 | it "allows 'url' to be missing if 'nothing' is true" do
42 | expect { Entities::Embed.new(nothing: true) }.not_to raise_error
43 | end
44 |
45 | it "doesn't allow 'url' to be set if 'nothing' is true" do
46 | expect {
47 | Entities::Embed.new(data.merge(nothing: true))
48 | }.to raise_error Entity::ValidationError, "Either 'url' must be set or 'nothing' must be 'true'"
49 | end
50 |
51 | it "doesn't allow 'url' to be missing if 'nothing' is not true" do
52 | expect {
53 | Entities::Embed.new({})
54 | }.to raise_error Entity::ValidationError, "Either 'url' must be set or 'nothing' must be 'true'"
55 | end
56 | end
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/event_participation_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::EventParticipation do
5 | let(:parent) { Fabricate(:event, author: bob) }
6 | let(:parent_entity) { Fabricate(:related_entity, author: bob.diaspora_id) }
7 | let(:data) {
8 | Fabricate.attributes_for(
9 | :event_participation_entity,
10 | author: alice.diaspora_id,
11 | parent_guid: parent.guid,
12 | parent: parent_entity
13 | ).tap {|hash| add_signatures(hash) }
14 | }
15 |
16 | let(:xml) { <<~XML }
17 |
18 | #{data[:author]}
19 | #{data[:guid]}
20 | #{parent.guid}
21 | #{data[:status]}
22 | #{data[:edited_at].utc.iso8601}
23 | #{data[:author_signature]}
24 |
25 | XML
26 |
27 | let(:string) { "EventParticipation:#{data[:guid]}:#{parent.guid}" }
28 |
29 | it_behaves_like "an Entity subclass"
30 |
31 | it_behaves_like "an XML Entity"
32 |
33 | it_behaves_like "a relayable Entity"
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/event_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::Event do
5 | let(:location) { Fabricate(:location_entity) }
6 | let(:data) {
7 | Fabricate.attributes_for(:event_entity).merge(author: alice.diaspora_id, location: location)
8 | }
9 |
10 | let(:xml) { <<~XML }
11 |
12 | #{data[:author]}
13 | #{data[:guid]}
14 | #{data[:edited_at].utc.iso8601}
15 | #{data[:summary]}
16 | #{data[:description]}
17 | #{data[:start].utc.iso8601}
18 | #{data[:end].utc.iso8601}
19 | #{data[:all_day]}
20 | #{data[:timezone]}
21 |
22 | #{location.address}
23 | #{location.lat}
24 | #{location.lng}
25 |
26 |
27 | XML
28 |
29 | let(:string) { "Event:#{data[:guid]}" }
30 |
31 | it_behaves_like "an Entity subclass"
32 |
33 | it_behaves_like "an XML Entity"
34 |
35 | context "default values" do
36 | it "uses default values" do
37 | minimal_xml = <<~XML
38 |
39 | #{data[:author]}
40 | #{data[:guid]}
41 | #{data[:summary]}
42 | #{data[:start].utc.iso8601}
43 |
44 | XML
45 |
46 | parsed_xml = Nokogiri::XML(minimal_xml).root
47 | parsed_instance = Entity.entity_class(parsed_xml.name).from_xml(parsed_xml)
48 | expect(parsed_instance.end).to be_nil
49 | expect(parsed_instance.all_day).to be_falsey
50 | expect(parsed_instance.timezone).to be_nil
51 | expect(parsed_instance.description).to be_nil
52 | expect(parsed_instance.location).to be_nil
53 | end
54 | end
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/location_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::Location do
5 | let(:data) { Fabricate.attributes_for(:location_entity) }
6 |
7 | let(:xml) { <<~XML }
8 |
9 | #{data[:address]}
10 | #{data[:lat]}
11 | #{data[:lng]}
12 |
13 | XML
14 |
15 | let(:json) { <<~JSON }
16 | {
17 | "entity_type": "location",
18 | "entity_data": {
19 | "address": "#{data[:address]}",
20 | "lat": "#{data[:lat]}",
21 | "lng": "#{data[:lng]}"
22 | }
23 | }
24 | JSON
25 |
26 | let(:string) { "Location" }
27 |
28 | it_behaves_like "an Entity subclass"
29 |
30 | it_behaves_like "an XML Entity"
31 |
32 | it_behaves_like "a JSON Entity"
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/message_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::Message do
5 | let(:data) { Fabricate.attributes_for(:message_entity, author: alice.diaspora_id) }
6 |
7 | let(:xml) { <<~XML }
8 |
9 | #{data[:author]}
10 | #{data[:guid]}
11 | #{data[:text]}
12 | #{data[:created_at].utc.iso8601}
13 | #{data[:edited_at].utc.iso8601}
14 | #{data[:conversation_guid]}
15 |
16 | XML
17 |
18 | let(:string) { "Message:#{data[:guid]}:#{data[:conversation_guid]}" }
19 |
20 | it_behaves_like "an Entity subclass"
21 |
22 | it_behaves_like "an XML Entity"
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/person_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::Person do
5 | let(:data) { Fabricate.attributes_for(:person_entity) }
6 |
7 | let(:xml) { <<~XML }
8 |
9 | #{data[:guid]}
10 | #{data[:author]}
11 | #{data[:url]}
12 |
13 | #{data[:profile].author}
14 | #{data[:profile].edited_at.utc.iso8601}
15 | #{data[:profile].full_name}
16 | #{data[:profile].first_name}
17 | #{data[:profile].image_url}
18 | #{data[:profile].image_url}
19 | #{data[:profile].image_url}
20 | #{data[:profile].bio}
21 | #{data[:profile].birthday}
22 | #{data[:profile].gender}
23 | #{data[:profile].location}
24 | #{data[:profile].searchable}
25 | #{data[:profile].public}
26 | #{data[:profile].nsfw}
27 | #{data[:profile].tag_string}
28 |
29 | #{data[:exported_key]}
30 |
31 | XML
32 |
33 | let(:string) { "Person:#{data[:guid]}" }
34 |
35 | it_behaves_like "an Entity subclass"
36 |
37 | it_behaves_like "an XML Entity"
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/poll_answer_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::PollAnswer do
5 | let(:data) { Fabricate.attributes_for(:poll_answer_entity) }
6 |
7 | let(:xml) { <<~XML }
8 |
9 | #{data[:guid]}
10 | #{data[:answer]}
11 |
12 | XML
13 |
14 | let(:json) { <<~JSON }
15 | {
16 | "entity_type": "poll_answer",
17 | "entity_data": {
18 | "guid": "#{data[:guid]}",
19 | "answer": "#{data[:answer]}"
20 | }
21 | }
22 | JSON
23 |
24 | let(:string) { "PollAnswer:#{data[:guid]}" }
25 |
26 | it_behaves_like "an Entity subclass"
27 |
28 | it_behaves_like "an XML Entity"
29 |
30 | it_behaves_like "a JSON Entity"
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/poll_participation_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::PollParticipation do
5 | let(:parent) { Fabricate(:poll, author: bob) }
6 | let(:parent_entity) { Fabricate(:related_entity, author: bob.diaspora_id) }
7 | let(:data) {
8 | Fabricate.attributes_for(
9 | :poll_participation_entity,
10 | author: alice.diaspora_id,
11 | parent_guid: parent.guid,
12 | parent: parent_entity
13 | ).tap {|hash| add_signatures(hash) }
14 | }
15 |
16 | let(:xml) { <<~XML }
17 |
18 | #{data[:author]}
19 | #{data[:guid]}
20 | #{parent.guid}
21 | #{data[:poll_answer_guid]}
22 | #{data[:author_signature]}
23 |
24 | XML
25 |
26 | let(:json) { <<~JSON }
27 | {
28 | "entity_type": "poll_participation",
29 | "entity_data": {
30 | "author": "#{data[:author]}",
31 | "guid": "#{data[:guid]}",
32 | "parent_guid": "#{parent.guid}",
33 | "author_signature": "#{data[:author_signature]}",
34 | "poll_answer_guid": "#{data[:poll_answer_guid]}"
35 | },
36 | "property_order": [
37 | "author",
38 | "guid",
39 | "parent_guid",
40 | "poll_answer_guid"
41 | ]
42 | }
43 | JSON
44 |
45 | let(:string) { "PollParticipation:#{data[:guid]}:#{parent.guid}" }
46 |
47 | it_behaves_like "an Entity subclass"
48 |
49 | it_behaves_like "an XML Entity"
50 |
51 | it_behaves_like "a JSON Entity"
52 |
53 | it_behaves_like "a relayable Entity"
54 |
55 | it_behaves_like "a relayable JSON entity"
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/poll_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::Poll do
5 | let(:data) { Fabricate.attributes_for(:poll_entity) }
6 |
7 | let(:xml) { <<~XML }
8 |
9 | #{data[:guid]}
10 | #{data[:question]}
11 | #{data[:poll_answers].map {|a| indent(a.to_xml.to_s, 2) }.join("\n")}
12 |
13 | XML
14 |
15 | let(:json) { <<~JSON }
16 | {
17 | "entity_type": "poll",
18 | "entity_data": {
19 | "guid": "#{data[:guid]}",
20 | "question": "#{data[:question]}",
21 | "poll_answers": [
22 | #{data[:poll_answers].map {|a| indent(JSON.pretty_generate(a.to_json), 6) }.join(",\n")}
23 | ]
24 | }
25 | }
26 | JSON
27 |
28 | let(:string) { "Poll:#{data[:guid]}" }
29 |
30 | it_behaves_like "an Entity subclass"
31 |
32 | it_behaves_like "an XML Entity"
33 |
34 | it_behaves_like "a JSON Entity"
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/entities/signable_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Entities::Signable do
5 | TEST_STRING_VALUE = "abc123"
6 |
7 | class TestSignableEntity < Entity
8 | include Entities::Signable
9 |
10 | property :my_signature, :string, default: nil
11 |
12 | def signature_data
13 | TEST_STRING_VALUE
14 | end
15 | end
16 |
17 | describe "#signature_data" do
18 | it "raises NotImplementedError when not overridden" do
19 | class TestEntity < Entity
20 | include Entities::Signable
21 | end
22 |
23 | expect {
24 | TestEntity.new({}).signature_data
25 | }.to raise_error(NotImplementedError)
26 | end
27 | end
28 |
29 | it_behaves_like "a signable" do
30 | let(:test_class) { TestSignableEntity }
31 | let(:test_string) { TEST_STRING_VALUE }
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/parsers/base_parser_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Parsers::BaseParser do
5 | describe ".parse" do
6 | it "raises NotImplementedError error" do
7 | expect {
8 | Parsers::BaseParser.new(Entity).parse
9 | }.to raise_error(NotImplementedError, "you must override this method when creating your own parser")
10 | end
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/parsers/relayable_json_parser_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Parsers::RelayableJsonParser do
5 | describe ".parse" do
6 | let(:entity_class) { Entities::SomeRelayable }
7 | let(:json_parser) { Parsers::RelayableJsonParser.new(entity_class) }
8 | include_examples ".parse parse error",
9 | "Required property is missing in JSON object: property_order",
10 | '{"entity_type": "some_relayable", "entity_data": {}}'
11 |
12 | it "returns property order as a second argument" do
13 | json = JSON.parse <<~JSON
14 | {
15 | "entity_type": "some_relayable",
16 | "property_order": ["property", "guid", "author"],
17 | "entity_data": {
18 | "author": "id@example.tld",
19 | "guid": "im a guid",
20 | "property": "value"
21 | }
22 | }
23 | JSON
24 | parsed_data = json_parser.parse(json)
25 | expect(parsed_data[0]).to be_a(Hash)
26 | expect(parsed_data[0][:guid]).to eq("im a guid")
27 | expect(parsed_data[0][:property]).to eq("value")
28 | expect(parsed_data[0][:author]).to eq("id@example.tld")
29 | expect(parsed_data[1]).to eq(%w[property guid author])
30 | end
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/parsers/relayable_xml_parser_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Parsers::RelayableXmlParser do
5 | describe ".parse" do
6 | let(:entity_class) { Entities::SomeRelayable }
7 | let(:xml_parser) { Parsers::RelayableXmlParser.new(entity_class) }
8 | it "passes order of the XML elements as a second argument in the returned list" do
9 | xml_object = Nokogiri::XML(<<~XML).root
10 |
11 | im a guid
12 | value
13 | id@example.tld
14 |
15 | XML
16 |
17 | parsed_data = xml_parser.parse(xml_object)
18 | expect(parsed_data[0]).to be_a(Hash)
19 | expect(parsed_data[0][:guid]).to eq("im a guid")
20 | expect(parsed_data[0][:property]).to eq("value")
21 | expect(parsed_data[0][:author]).to eq("id@example.tld")
22 | expect(parsed_data[1]).to eq(%i[guid property author])
23 | end
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/salmon/aes_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Salmon::AES do
5 | let(:data) { "test data string" }
6 |
7 | describe ".generate_key_and_iv" do
8 | it "generates a random key and iv" do
9 | key_and_iv = Salmon::AES.generate_key_and_iv
10 |
11 | expect(key_and_iv[:key]).not_to be_empty
12 | expect(key_and_iv[:iv]).not_to be_empty
13 | end
14 |
15 | it "generates a different key and iv every time" do
16 | key_and_iv = Salmon::AES.generate_key_and_iv
17 | key_and_iv2 = Salmon::AES.generate_key_and_iv
18 |
19 | expect(key_and_iv[:key]).not_to eq(key_and_iv2[:key])
20 | expect(key_and_iv[:iv]).not_to eq(key_and_iv2[:iv])
21 | end
22 | end
23 |
24 | describe ".encrypt" do
25 | let(:key_and_iv) { Salmon::AES.generate_key_and_iv }
26 |
27 | it "encrypts the data" do
28 | ciphertext = Salmon::AES.encrypt(data, key_and_iv[:key], key_and_iv[:iv])
29 |
30 | expect(Base64.decode64(ciphertext)).not_to eq(data)
31 | end
32 |
33 | it "raises an error when the data is missing or the wrong type" do
34 | [nil, 1234, true, :symbol].each do |val|
35 | expect {
36 | Salmon::AES.encrypt(val, key_and_iv[:key], key_and_iv[:iv])
37 | }.to raise_error ArgumentError
38 | end
39 | end
40 | end
41 |
42 | describe ".decrypt" do
43 | it "decrypts what it has encrypted" do
44 | key = Salmon::AES.generate_key_and_iv
45 | ciphertext = Salmon::AES.encrypt(data, key[:key], key[:iv])
46 |
47 | decrypted_data = Salmon::AES.decrypt(ciphertext, key[:key], key[:iv])
48 |
49 | expect(decrypted_data).to eq(data)
50 | end
51 |
52 | it "raises an error when the params are missing or the wrong type" do
53 | [nil, 1234, true, :symbol].each do |val|
54 | expect {
55 | Salmon::AES.decrypt(val, val, val)
56 | }.to raise_error ArgumentError
57 | end
58 | end
59 | end
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/schemas_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "diaspora_federation/schemas"
4 |
5 | module DiasporaFederation
6 | describe Schemas do
7 | describe ".federation_entities" do
8 | it "returns the parsed federation_entities JSON schema" do
9 | schema = DiasporaFederation::Schemas.federation_entities
10 | expect(schema).to be_a(Hash)
11 | expect(schema["id"]).to eq(DiasporaFederation::Schemas::FEDERATION_ENTITIES_URI)
12 | end
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/account_deletion_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::AccountDeletionValidator do
5 | let(:entity) { :account_deletion_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | it_behaves_like "a diaspora* ID validator" do
10 | let(:property) { :author }
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/account_migration_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::AccountMigrationValidator do
5 | let(:entity) { :account_migration_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | it_behaves_like "a diaspora* ID validator" do
10 | let(:property) { :author }
11 | end
12 |
13 | describe "#profile" do
14 | it_behaves_like "a property with a value validation/restriction" do
15 | let(:property) { :profile }
16 | let(:wrong_values) { [nil] }
17 | let(:correct_values) { [] }
18 | end
19 | end
20 |
21 | describe "#old_identity" do
22 | it_behaves_like "a diaspora* ID validator" do
23 | let(:property) { :old_identity }
24 | end
25 | end
26 |
27 | describe "#remote_photo_path" do
28 | let(:property) { :remote_photo_path }
29 |
30 | it_behaves_like "a property with a value validation/restriction" do
31 | let(:wrong_values) { [] }
32 | let(:correct_values) { [nil] }
33 | end
34 |
35 | it_behaves_like "a url path validator"
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/comment_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::CommentValidator do
5 | let(:entity) { :comment_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | it_behaves_like "a relayable validator"
10 |
11 | describe "#text" do
12 | it_behaves_like "a property with a value validation/restriction" do
13 | let(:property) { :text }
14 | let(:wrong_values) { ["", "a" * 65_536] }
15 | let(:correct_values) { ["a" * 65_535] }
16 | end
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/contact_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::ContactValidator do
5 | let(:entity) { :contact_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | %i[author recipient].each do |prop|
10 | describe "##{prop}" do
11 | it_behaves_like "a diaspora* ID validator" do
12 | let(:property) { prop }
13 | end
14 | end
15 | end
16 |
17 | %i[following sharing blocking].each do |prop|
18 | describe "##{prop}" do
19 | it_behaves_like "a boolean validator" do
20 | let(:property) { prop }
21 | end
22 | end
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/conversation_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::ConversationValidator do
5 | let(:entity) { :conversation_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | it_behaves_like "a diaspora* ID validator" do
10 | let(:property) { :author }
11 | end
12 |
13 | it_behaves_like "a guid validator" do
14 | let(:property) { :guid }
15 | end
16 |
17 | describe "#subject" do
18 | it_behaves_like "a property with a value validation/restriction" do
19 | let(:property) { :subject }
20 | let(:wrong_values) { [nil, "", "a" * 256] }
21 | let(:correct_values) { ["a" * 255] }
22 | end
23 | end
24 |
25 | describe "#messages" do
26 | it_behaves_like "a property with a value validation/restriction" do
27 | let(:property) { :messages }
28 | let(:wrong_values) { [nil] }
29 | let(:correct_values) { [[], [Fabricate(:message_entity)]] }
30 | end
31 | end
32 |
33 | describe "#participant_ids" do
34 | it_behaves_like "a property with a value validation/restriction" do
35 | let(:property) { :participants }
36 | let(:wrong_values) { ["", "foo;bar", Fabricate.sequence(:diaspora_id)] }
37 | let(:correct_values) {
38 | [
39 | Array.new(2) { Fabricate.sequence(:diaspora_id) }.join(";"),
40 | Array.new(21) { Fabricate.sequence(:diaspora_id) }.join(";")
41 | ]
42 | }
43 | end
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/embed_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::EmbedValidator do
5 | let(:entity) { :embed_entity }
6 | it_behaves_like "a common validator"
7 |
8 | describe "#url" do
9 | it_behaves_like "a property with a value validation/restriction" do
10 | let(:property) { :url }
11 | let(:wrong_values) { %w[https://asdf$%.com example.com] }
12 | let(:correct_values) { [nil, "https://example.org", "https://example.org/index.html"] }
13 | end
14 | end
15 |
16 | describe "#title" do
17 | it_behaves_like "a length validator" do
18 | let(:property) { :title }
19 | let(:length) { 255 }
20 | end
21 | end
22 |
23 | describe "#description" do
24 | it_behaves_like "a length validator" do
25 | let(:property) { :description }
26 | let(:length) { 65_535 }
27 | end
28 | end
29 |
30 | describe "#image" do
31 | it_behaves_like "a property with a value validation/restriction" do
32 | let(:property) { :image }
33 | let(:wrong_values) { %w[https://asdf$%.com example.com] }
34 | let(:correct_values) { [nil] }
35 | end
36 |
37 | it_behaves_like "a url path validator" do
38 | let(:property) { :image }
39 | end
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/event_participation_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::EventParticipationValidator do
5 | let(:entity) { :event_participation_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | it_behaves_like "a relayable validator"
10 |
11 | describe "#status" do
12 | it_behaves_like "a property with a value validation/restriction" do
13 | let(:property) { :status }
14 | let(:wrong_values) { ["", "yes", "foobar"] }
15 | let(:correct_values) { %w[accepted declined tentative] }
16 | end
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/event_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::EventValidator do
5 | let(:entity) { :event_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | it_behaves_like "a diaspora* ID validator" do
10 | let(:property) { :author }
11 | end
12 |
13 | it_behaves_like "a guid validator" do
14 | let(:property) { :guid }
15 | end
16 |
17 | describe "#summary" do
18 | it_behaves_like "a property with a value validation/restriction" do
19 | let(:property) { :summary }
20 | let(:wrong_values) { ["a" * 256, nil, ""] }
21 | let(:correct_values) { ["a" * 255] }
22 | end
23 | end
24 |
25 | describe "#description" do
26 | it_behaves_like "a property with a value validation/restriction" do
27 | let(:property) { :description }
28 | let(:wrong_values) { ["a" * 65_536] }
29 | let(:correct_values) { ["a" * 65_535, nil, ""] }
30 | end
31 | end
32 |
33 | describe "#start" do
34 | it_behaves_like "a property with a value validation/restriction" do
35 | let(:property) { :start }
36 | let(:wrong_values) { [nil] }
37 | let(:correct_values) { [Time.now.utc] }
38 | end
39 | end
40 |
41 | describe "#end" do
42 | it_behaves_like "a property with a value validation/restriction" do
43 | let(:property) { :end }
44 | let(:wrong_values) { [] }
45 | let(:correct_values) { [nil, Time.now.utc] }
46 | end
47 | end
48 |
49 | describe "#all_day" do
50 | it_behaves_like "a boolean validator" do
51 | let(:property) { :all_day }
52 | end
53 | end
54 |
55 | describe "#timezone" do
56 | it_behaves_like "a property with a value validation/restriction" do
57 | let(:property) { :timezone }
58 | let(:wrong_values) { ["foobar"] }
59 | let(:correct_values) { [nil, "Europe/Berlin", "America/Argentina/ComodRivadavia"] }
60 | end
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/h_card_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::HCardValidator do
5 | let(:entity) { :h_card }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | describe "#full_name" do
10 | it_behaves_like "a name validator" do
11 | let(:property) { :full_name }
12 | let(:length) { 70 }
13 | end
14 | end
15 |
16 | %i[first_name last_name].each do |prop|
17 | describe "##{prop}" do
18 | it_behaves_like "a name validator" do
19 | let(:property) { prop }
20 | let(:length) { 32 }
21 | end
22 | end
23 | end
24 |
25 | %i[photo_large_url photo_medium_url photo_small_url].each do |prop|
26 | describe "##{prop}" do
27 | it_behaves_like "a property that mustn't be empty" do
28 | let(:property) { prop }
29 | end
30 |
31 | it_behaves_like "a url path validator" do
32 | let(:property) { prop }
33 | end
34 | end
35 | end
36 |
37 | describe "#searchable" do
38 | it_behaves_like "a boolean validator" do
39 | let(:property) { :searchable }
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/like_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::LikeValidator do
5 | let(:entity) { :like_entity }
6 | it_behaves_like "a common validator"
7 |
8 | it_behaves_like "a relayable validator"
9 |
10 | describe "#parent_type" do
11 | it_behaves_like "a property with a value validation/restriction" do
12 | let(:property) { :parent_type }
13 | let(:wrong_values) { [nil, "", "any", "Postxxx", "post"] }
14 | let(:correct_values) { %w[Post Comment] }
15 | end
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/location_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::LocationValidator do
5 | let(:entity) { :location_entity }
6 | it_behaves_like "a common validator"
7 |
8 | %i[lat lng].each do |prop|
9 | describe "##{prop}" do
10 | it_behaves_like "a property that mustn't be empty" do
11 | let(:property) { prop }
12 | end
13 | end
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/message_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::MessageValidator do
5 | let(:entity) { :message_entity }
6 | it_behaves_like "a common validator"
7 |
8 | it_behaves_like "a diaspora* ID validator" do
9 | let(:property) { :author }
10 | end
11 |
12 | describe "#guid" do
13 | it_behaves_like "a guid validator" do
14 | let(:property) { :guid }
15 | end
16 | end
17 |
18 | describe "#conversation_guid" do
19 | it_behaves_like "a guid validator" do
20 | let(:property) { :conversation_guid }
21 | end
22 | end
23 |
24 | describe "#text" do
25 | it_behaves_like "a property with a value validation/restriction" do
26 | let(:property) { :text }
27 | let(:wrong_values) { ["", "a" * 65_536] }
28 | let(:correct_values) { ["a" * 65_535] }
29 | end
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/participation_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::ParticipationValidator do
5 | let(:entity) { :participation_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | it_behaves_like "a diaspora* ID validator" do
10 | let(:property) { :author }
11 | end
12 |
13 | describe "#guid" do
14 | it_behaves_like "a guid validator" do
15 | let(:property) { :guid }
16 | end
17 | end
18 |
19 | describe "#parent_guid" do
20 | it_behaves_like "a guid validator" do
21 | let(:property) { :parent_guid }
22 | end
23 | end
24 |
25 | describe "#parent_type" do
26 | it_behaves_like "a property with a value validation/restriction" do
27 | let(:property) { :parent_type }
28 | let(:wrong_values) { [nil, "", "any", "Postxxx", "post"] }
29 | let(:correct_values) { ["Post"] }
30 | end
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/person_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::PersonValidator do
5 | let(:entity) { :person_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | it_behaves_like "a diaspora* ID validator" do
10 | let(:property) { :author }
11 | end
12 |
13 | it_behaves_like "a guid validator" do
14 | let(:property) { :guid }
15 | end
16 |
17 | describe "#url" do
18 | it_behaves_like "a url validator without path" do
19 | let(:property) { :url }
20 | end
21 | end
22 |
23 | describe "#profile" do
24 | it_behaves_like "a property with a value validation/restriction" do
25 | let(:property) { :profile }
26 | let(:wrong_values) { [nil] }
27 | let(:correct_values) { [] }
28 | end
29 | end
30 |
31 | it_behaves_like "a public key validator" do
32 | let(:property) { :exported_key }
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/photo_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::PhotoValidator do
5 | let(:entity) { :photo_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | it_behaves_like "a diaspora* ID validator" do
10 | let(:property) { :author }
11 | end
12 |
13 | describe "#guid" do
14 | it_behaves_like "a guid validator" do
15 | let(:property) { :guid }
16 | end
17 | end
18 |
19 | describe "#status_message_guid" do
20 | it_behaves_like "a nilable guid validator" do
21 | let(:property) { :status_message_guid }
22 | end
23 | end
24 |
25 | it_behaves_like "a boolean validator" do
26 | let(:property) { :public }
27 | end
28 |
29 | describe "#remote_photo_path" do
30 | let(:property) { :remote_photo_path }
31 |
32 | it_behaves_like "a property that mustn't be empty"
33 |
34 | it_behaves_like "a url path validator"
35 | end
36 |
37 | describe "#remote_photo_name" do
38 | it_behaves_like "a property that mustn't be empty" do
39 | let(:property) { :remote_photo_name }
40 | end
41 | end
42 |
43 | %i[height width].each do |prop|
44 | describe "##{prop}" do
45 | it_behaves_like "a property with a value validation/restriction" do
46 | let(:property) { prop }
47 | let(:wrong_values) { [true, :num, "asdf"] }
48 | let(:correct_values) { [123, "123", nil] }
49 | end
50 | end
51 | end
52 |
53 | describe "#text" do
54 | it_behaves_like "a property with a value validation/restriction" do
55 | let(:property) { :text }
56 | let(:wrong_values) { ["a" * 65_536] }
57 | let(:correct_values) { ["a" * 65_535, nil, ""] }
58 | end
59 | end
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/poll_answer_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::PollAnswerValidator do
5 | let(:entity) { :poll_answer_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | describe "#guid" do
10 | it_behaves_like "a guid validator" do
11 | let(:property) { :guid }
12 | end
13 | end
14 |
15 | describe "#answer" do
16 | it_behaves_like "a property with a value validation/restriction" do
17 | let(:property) { :answer }
18 | let(:wrong_values) { [nil, "", "a" * 256] }
19 | let(:correct_values) { ["a" * 255] }
20 | end
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/poll_participation_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::PollParticipationValidator do
5 | let(:entity) { :poll_participation_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | it_behaves_like "a relayable validator"
10 |
11 | describe "#poll_answer_guid" do
12 | it_behaves_like "a guid validator" do
13 | let(:property) { :poll_answer_guid }
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/poll_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::PollValidator do
5 | let(:entity) { :poll_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | describe "#guid" do
10 | it_behaves_like "a guid validator" do
11 | let(:property) { :guid }
12 | end
13 | end
14 |
15 | describe "#question" do
16 | it_behaves_like "a property with a value validation/restriction" do
17 | let(:property) { :question }
18 | let(:wrong_values) { [nil, "", "a" * 256] }
19 | let(:correct_values) { ["a" * 255] }
20 | end
21 | end
22 |
23 | describe "#poll_answers" do
24 | it_behaves_like "a property with a value validation/restriction" do
25 | let(:property) { :poll_answers }
26 | let(:wrong_values) { [nil, [Fabricate.attributes_for(:poll_answer_entity)]] }
27 | let(:correct_values) {
28 | [
29 | Array.new(2) { Fabricate(:poll_answer_entity) },
30 | Array.new(5) { Fabricate(:poll_answer_entity) }
31 | ]
32 | }
33 | end
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/related_entity_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::RelatedEntityValidator do
5 | let(:entity) { :related_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | it_behaves_like "a diaspora* ID validator" do
10 | let(:property) { :author }
11 | end
12 |
13 | %i[local public].each do |prop|
14 | it_behaves_like "a boolean validator" do
15 | let(:property) { prop }
16 | end
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/reshare_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::ReshareValidator do
5 | let(:entity) { :reshare_entity }
6 | it_behaves_like "a common validator"
7 |
8 | describe "#author" do
9 | it_behaves_like "a diaspora* ID validator" do
10 | let(:property) { :author }
11 | end
12 | end
13 |
14 | describe "#guid" do
15 | it_behaves_like "a guid validator" do
16 | let(:property) { :guid }
17 | end
18 | end
19 |
20 | describe "#root_guid" do
21 | it_behaves_like "a nilable guid validator" do
22 | let(:property) { :root_guid }
23 | end
24 | end
25 |
26 | describe "#root_author" do
27 | it_behaves_like "a property with a value validation/restriction" do
28 | let(:property) { :root_author }
29 | let(:wrong_values) { ["i am a weird diaspora* ID @@@ ### 12345"] }
30 | let(:correct_values) { [nil, "alice@example.org"] }
31 | end
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/retraction_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::RetractionValidator do
5 | let(:entity) { :retraction_entity }
6 | it_behaves_like "a common validator"
7 |
8 | it_behaves_like "a guid validator" do
9 | let(:property) { :target_guid }
10 | end
11 |
12 | it_behaves_like "a diaspora* ID validator" do
13 | let(:property) { :author }
14 | end
15 |
16 | describe "#target_type" do
17 | it_behaves_like "a property that mustn't be empty" do
18 | let(:property) { :target_type }
19 | end
20 | end
21 |
22 | describe "#target" do
23 | it_behaves_like "a property with a value validation/restriction" do
24 | let(:property) { :target }
25 | let(:wrong_values) { [nil] }
26 | let(:correct_values) { [Fabricate(:related_entity)] }
27 | end
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/rules/birthday_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | describe Validation::Rule::Birthday do
4 | it "will not accept parameters" do
5 | validator = Validation::Validator.new({})
6 | expect {
7 | validator.rule(:birthday, birthday: {param: true})
8 | }.to raise_error ArgumentError
9 | end
10 |
11 | it "has an error key" do
12 | expect(described_class.new.error_key).to eq(:birthday)
13 | end
14 |
15 | context "when validating" do
16 | before do
17 | stub_const("BirthdayHolder", Struct.new(:birthday))
18 | end
19 |
20 | it "validates a date object" do
21 | validator = Validation::Validator.new(BirthdayHolder.new(Date.new))
22 | validator.rule(:birthday, :birthday)
23 |
24 | expect(validator).to be_valid
25 | expect(validator.errors).to be_empty
26 | end
27 |
28 | it "validates a string" do
29 | validator = Validation::Validator.new(BirthdayHolder.new("2015-07-19"))
30 | validator.rule(:birthday, :birthday)
31 |
32 | expect(validator).to be_valid
33 | expect(validator.errors).to be_empty
34 | end
35 |
36 | it "allows nil and empty" do
37 | [nil, ""].each do |val|
38 | validator = Validation::Validator.new(BirthdayHolder.new(val))
39 | validator.rule(:birthday, :birthday)
40 |
41 | expect(validator).to be_valid
42 | expect(validator.errors).to be_empty
43 | end
44 | end
45 |
46 | it "fails for invalid date string" do
47 | validator = Validation::Validator.new(BirthdayHolder.new("i'm no date"))
48 | validator.rule(:birthday, :birthday)
49 |
50 | expect(validator).not_to be_valid
51 | expect(validator.errors).to include(:birthday)
52 | end
53 | end
54 | end
55 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/rules/not_nil_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | describe Validation::Rule::NotNil do
4 | it "will not accept parameters" do
5 | validator = Validation::Validator.new({})
6 | expect {
7 | validator.rule(:not_nil, not_nil: {param: true})
8 | }.to raise_error ArgumentError
9 | end
10 |
11 | it "has an error key" do
12 | expect(described_class.new.error_key).to eq(:not_nil)
13 | end
14 |
15 | context "when validating" do
16 | before do
17 | stub_const("ValueHolder", Struct.new(:value))
18 | end
19 |
20 | it "validates a string" do
21 | validator = Validation::Validator.new(ValueHolder.new("abcd"))
22 | validator.rule(:value, :not_nil)
23 |
24 | expect(validator).to be_valid
25 | expect(validator.errors).to be_empty
26 | end
27 |
28 | it "validates a object" do
29 | validator = Validation::Validator.new(ValueHolder.new(Object.new))
30 | validator.rule(:value, :not_nil)
31 |
32 | expect(validator).to be_valid
33 | expect(validator.errors).to be_empty
34 | end
35 |
36 | it "fails if it is nil" do
37 | validator = Validation::Validator.new(ValueHolder.new(nil))
38 | validator.rule(:value, :not_nil)
39 |
40 | expect(validator).not_to be_valid
41 | expect(validator.errors).to include(:value)
42 | end
43 |
44 | it "allows an empty string" do
45 | validator = Validation::Validator.new(ValueHolder.new(""))
46 | validator.rule(:value, :not_nil)
47 |
48 | expect(validator).to be_valid
49 | expect(validator.errors).to be_empty
50 | end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/status_message_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::StatusMessageValidator do
5 | let(:entity) { :status_message_entity }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | it_behaves_like "a diaspora* ID validator" do
10 | let(:property) { :author }
11 | end
12 |
13 | it_behaves_like "a guid validator" do
14 | let(:property) { :guid }
15 | end
16 |
17 | describe "#photos" do
18 | it_behaves_like "a property with a value validation/restriction" do
19 | let(:property) { :photos }
20 | let(:wrong_values) { [nil] }
21 | let(:correct_values) { [[], [Fabricate(:photo_entity)]] }
22 | end
23 | end
24 |
25 | it_behaves_like "a boolean validator" do
26 | let(:property) { :public }
27 | end
28 |
29 | describe "#text" do
30 | it_behaves_like "a property with a value validation/restriction" do
31 | let(:property) { :text }
32 | let(:wrong_values) { ["a" * 65_536] }
33 | let(:correct_values) { ["a" * 65_535, nil, ""] }
34 | end
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/spec/lib/diaspora_federation/validators/web_finger_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe Validators::WebFingerValidator do
5 | let(:entity) { :webfinger }
6 |
7 | it_behaves_like "a common validator"
8 |
9 | describe "#acct_uri" do
10 | it_behaves_like "a property that mustn't be empty" do
11 | let(:property) { :acct_uri }
12 | end
13 | end
14 |
15 | %i[hcard_url].each do |prop|
16 | describe "##{prop}" do
17 | it_behaves_like "a url validator without path" do
18 | let(:property) { prop }
19 | end
20 |
21 | it_behaves_like "a url path validator" do
22 | let(:property) { prop }
23 | end
24 | end
25 | end
26 |
27 | # optional urls
28 | %i[salmon_url profile_url atom_url].each do |prop|
29 | describe "##{prop}" do
30 | it_behaves_like "a property with a value validation/restriction" do
31 | let(:property) { prop }
32 | let(:wrong_values) { %w[https://asdf$%.com example.com] }
33 | let(:correct_values) { [nil] }
34 | end
35 |
36 | it_behaves_like "a url path validator" do
37 | let(:property) { prop }
38 | end
39 | end
40 | end
41 |
42 | describe "#seed_url" do
43 | it_behaves_like "a url validator without path" do
44 | let(:property) { :seed_url }
45 | end
46 | end
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/spec/routing/fetch_routing_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe ReceiveController, type: :routing do
5 | routes { DiasporaFederation::Engine.routes }
6 |
7 | let(:guid) { "12345678901234567890abcdefgh" }
8 |
9 | it "routes post fetch" do
10 | expect(get: "/fetch/post/#{guid}").to route_to(
11 | controller: "diaspora_federation/fetch",
12 | action: "fetch",
13 | type: "post",
14 | guid: guid
15 | )
16 | end
17 |
18 | it "routes post fetch" do
19 | expect(get: "/fetch/status_message/#{guid}").to route_to(
20 | controller: "diaspora_federation/fetch",
21 | action: "fetch",
22 | type: "status_message",
23 | guid: guid
24 | )
25 | end
26 |
27 | it "routes post fetch with GUID with dots (hubzilla)" do
28 | guid = "1234567890abcd@hubzilla.example.org"
29 | expect(get: "/fetch/post/#{guid}").to route_to(
30 | controller: "diaspora_federation/fetch",
31 | action: "fetch",
32 | type: "post",
33 | guid: guid
34 | )
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/spec/routing/receive_routing_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe ReceiveController, type: :routing do
5 | routes { DiasporaFederation::Engine.routes }
6 |
7 | it "routes POST public" do
8 | expect(post: "/receive/public").to route_to(
9 | controller: "diaspora_federation/receive",
10 | action: "public"
11 | )
12 | end
13 |
14 | it "routes POST private" do
15 | expect(post: "/receive/users/1234").to route_to(
16 | controller: "diaspora_federation/receive",
17 | action: "private",
18 | guid: "1234"
19 | )
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/spec/routing/webfinger_routing_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiasporaFederation
4 | describe ReceiveController, type: :routing do
5 | routes { DiasporaFederation::Engine.routes }
6 |
7 | it "routes GET webfinger" do
8 | expect(get: "/.well-known/webfinger").to route_to(
9 | controller: "diaspora_federation/webfinger",
10 | action: "webfinger"
11 | )
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/spec/support/fixture_builder.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # set default users as initial database for each test
4 | RSpec.configure do |config|
5 | config.before(:suite) do
6 | Person.reset_database
7 | Fabricate(:user, diaspora_id: "alice@localhost:3000")
8 | Fabricate(:user, diaspora_id: "bob@localhost:3000")
9 | Person.init_database = Person.database
10 | end
11 |
12 | config.after(:each) do
13 | Entity.reset_database
14 | Person.reset_database
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/spec/support/helper_methods.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # default users
4 | def alice
5 | @alice ||= Person.find_by(diaspora_id: "alice@localhost:3000")
6 | end
7 |
8 | def bob
9 | @bob ||= Person.find_by(diaspora_id: "bob@localhost:3000")
10 | end
11 |
12 | # callback expectation helper
13 | def expect_callback(*opts)
14 | expect(DiasporaFederation.callbacks).to receive(:trigger).with(*opts)
15 | end
16 |
17 | # signature methods
18 | def add_signatures(hash, klass=described_class)
19 | properties = klass.new(hash).send(:xml_elements)
20 | hash[:author_signature] = properties[:author_signature]
21 | end
22 |
23 | def sign_with_key(privkey, signature_data)
24 | Base64.strict_encode64(privkey.sign(OpenSSL::Digest.new("SHA256"), signature_data))
25 | end
26 |
27 | def verify_signature(pubkey, signature, signed_string)
28 | pubkey.verify(OpenSSL::Digest.new("SHA256"), Base64.decode64(signature), signed_string)
29 | end
30 |
31 | # time helper
32 | def change_time(time, options={})
33 | new_hour = options.fetch(:hour, time.hour)
34 | new_min = options.fetch(:min, options[:hour] ? 0 : time.min)
35 | new_sec = options.fetch(:sec, options[:hour] || options[:min] ? 0 : time.sec)
36 |
37 | Time.utc(time.year, time.month, time.day, new_hour, new_min, new_sec)
38 | end
39 |
40 | # indent helper
41 | def indent(string, amount)
42 | string.gsub(/^/, " " * amount)
43 | end
44 |
--------------------------------------------------------------------------------
/spec/support/shared_magic_envelope_specs.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | shared_examples "a MagicEnvelope instance" do
4 | before do
5 | allow(DiasporaFederation.callbacks).to receive(:trigger).with(
6 | :fetch_public_key, sender
7 | ).and_return(privkey.public_key)
8 | end
9 |
10 | it "is an instance of MagicEnvelope" do
11 | expect(subject).to be_an_instance_of DiasporaFederation::Salmon::MagicEnvelope
12 | end
13 |
14 | it "should match the sender" do
15 | expect(subject.sender).to eq(sender)
16 | end
17 |
18 | it "returns the entity" do
19 | entity = subject.payload
20 | expect(entity).to be_an_instance_of DiasporaFederation::Entities::TestEntity
21 | expect(entity.test).to eq(payload.test)
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/support/shared_parser_specs.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | shared_examples ".parse parse error" do |reason, json|
4 | it "raises error when #{reason}" do
5 | expect {
6 | json_parser.parse(JSON.parse(json))
7 | }.to raise_error DiasporaFederation::Parsers::JsonParser::DeserializationError, reason
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/README.rdoc:
--------------------------------------------------------------------------------
1 | == README
2 |
3 | This is a dummy rails application to debug the diaspora federation gem.
--------------------------------------------------------------------------------
/test/dummy/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Add your own tasks in files placed in lib/tasks ending in .rake,
4 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
5 |
6 | require File.expand_path("config/application", __dir__)
7 |
8 | Rails.application.load_tasks
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/entity.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Entity
4 | attr_accessor :author, :guid
5 | attr_reader :entity_type
6 |
7 | def initialize(entity_type)
8 | @entity_type = entity_type
9 | @guid = UUID.generate(:compact)
10 | end
11 |
12 | def save!
13 | Entity.database[entity_type][guid] = self
14 | end
15 |
16 | class << self
17 | def find_by(opts)
18 | database[opts[:entity_type]][opts[:guid]]
19 | end
20 |
21 | def database
22 | @database ||= Hash.new({})
23 | end
24 |
25 | def reset_database
26 | @database = nil
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/test/dummy/app/models/person.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Person
4 | attr_accessor :diaspora_id, :url, :guid, :serialized_public_key, :serialized_private_key
5 |
6 | def initialize
7 | @guid = UUID.generate(:compact)
8 | end
9 |
10 | def private_key; OpenSSL::PKey::RSA.new(serialized_private_key) end
11 | def public_key; OpenSSL::PKey::RSA.new(serialized_public_key) end
12 |
13 | def alias_url; "#{url}people/#{guid}" end
14 | def hcard_url; "#{url}hcard/users/#{guid}" end
15 | def profile_url; "#{url}u/#{nickname}" end
16 | def atom_url; "#{url}public/#{nickname}.atom" end
17 | def salmon_url; "#{url}receive/users/#{guid}" end
18 | def subscribe_url; "#{url}people?q={uri}" end
19 |
20 | def nickname; diaspora_id.split("@")[0] end
21 |
22 | def photo_default_url; "#{url}assets/user/default.png" end
23 |
24 | def searchable; true end
25 | def full_name; "Dummy User" end
26 | def first_name; "Dummy" end
27 | def last_name; "User" end
28 |
29 | def save!
30 | Person.database[:diaspora_id][diaspora_id] = self
31 | Person.database[:guid][guid] = self
32 | end
33 |
34 | class << self
35 | attr_writer :init_database
36 |
37 | def find_by(opts)
38 | return database[:diaspora_id][opts[:diaspora_id]] if opts[:diaspora_id]
39 |
40 | database[:guid][opts[:guid]]
41 | end
42 |
43 | def database
44 | @database ||= @init_database || {diaspora_id: {}, guid: {}}
45 | end
46 |
47 | def reset_database
48 | @database = nil
49 | end
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/test/dummy/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_PATH = File.expand_path("../config/application", __dir__)
3 | require_relative "../config/boot"
4 | require "rails/commands"
5 |
--------------------------------------------------------------------------------
/test/dummy/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative "../config/boot"
3 | require "rake"
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/test/dummy/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require "fileutils"
3 |
4 | # path to your application root.
5 | APP_ROOT = File.expand_path("..", __dir__)
6 |
7 | def system!(*args)
8 | system(*args) || abort("\n== Command #{args} failed ==")
9 | end
10 |
11 | FileUtils.chdir APP_ROOT do
12 | # This script is a way to set up or update your development environment automatically.
13 | # This script is idempotent, so that you can run it at any time and get an expectable outcome.
14 | # Add necessary setup steps to this file.
15 |
16 | puts "== Installing dependencies =="
17 | system! "gem install bundler --conservative"
18 | system("bundle check") || system!("bundle install")
19 |
20 | puts "\n== Removing old logs and tempfiles =="
21 | system! "bin/rails log:clear tmp:clear"
22 |
23 | puts "\n== Restarting application server =="
24 | system! "bin/rails restart"
25 | end
26 |
--------------------------------------------------------------------------------
/test/dummy/config.ru:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # This file is used by Rack-based servers to start the application.
4 |
5 | require_relative "config/environment"
6 |
7 | run Rails.application
8 | Rails.application.load_server
9 |
--------------------------------------------------------------------------------
/test/dummy/config/application.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative "boot"
4 |
5 | require "rails"
6 | # Pick the frameworks you want:
7 | # require "active_model/railtie"
8 | # require "active_job/railtie"
9 | # require "active_record/railtie"
10 | # require "active_storage/engine"
11 | require "action_controller/railtie"
12 | # require "action_mailer/railtie"
13 | # require "action_mailbox/engine"
14 | # require "action_text/engine"
15 | require "action_view/railtie"
16 | # require "action_cable/engine"
17 | require "rails/test_unit/railtie"
18 |
19 | # Require the gems listed in Gemfile, including any gems
20 | # you've limited to :test, :development, or :production.
21 | Bundler.require(*Rails.groups)
22 | require "diaspora_federation/rails"
23 |
24 | module Dummy
25 | class Application < Rails::Application
26 | # Initialize configuration defaults for originally generated Rails version.
27 | config.load_defaults(ENV["RAILS_VERSION"] || "7.0")
28 |
29 | # Configuration for the application, engines, and railties goes here.
30 | #
31 | # These settings can be overridden in specific environments using the files
32 | # in config/environments, which are processed later.
33 | #
34 | # config.time_zone = "Central Time (US & Canada)"
35 | # config.eager_load_paths << Rails.root.join("extras")
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/test/dummy/config/boot.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile", __dir__)
4 |
5 | require "bundler/setup" # Set up gems listed in the Gemfile.
6 |
--------------------------------------------------------------------------------
/test/dummy/config/environment.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Load the Rails application.
4 | require_relative "application"
5 |
6 | # Initialize the Rails application.
7 | Rails.application.initialize!
8 |
--------------------------------------------------------------------------------
/test/dummy/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "active_support/core_ext/integer/time"
4 |
5 | Rails.application.configure do
6 | # Settings specified here will take precedence over those in config/application.rb.
7 |
8 | # In the development environment your application's code is reloaded any time
9 | # it changes. This slows down response time but is perfect for development
10 | # since you don't have to restart the web server when you make code changes.
11 | config.cache_classes = false
12 |
13 | # Do not eager load code on boot.
14 | config.eager_load = false
15 |
16 | # Show full error reports.
17 | config.consider_all_requests_local = true
18 |
19 | # Enable server timing
20 | config.server_timing = true
21 |
22 | # Enable/disable caching. By default caching is disabled.
23 | # Run rails dev:cache to toggle caching.
24 | if Rails.root.join("tmp/caching-dev.txt").exist?
25 | config.action_controller.perform_caching = true
26 | config.action_controller.enable_fragment_cache_logging = true
27 |
28 | config.cache_store = :memory_store
29 | config.public_file_server.headers = {
30 | "Cache-Control" => "public, max-age=#{2.days.to_i}"
31 | }
32 | else
33 | config.action_controller.perform_caching = false
34 |
35 | config.cache_store = :null_store
36 | end
37 |
38 | # Print deprecation notices to the Rails logger.
39 | config.active_support.deprecation = :log
40 |
41 | # Raise exceptions for disallowed deprecations.
42 | config.active_support.disallowed_deprecation = :raise
43 |
44 | # Tell Active Support which deprecation messages to disallow.
45 | config.active_support.disallowed_deprecation_warnings = []
46 |
47 | # Raises error for missing translations.
48 | # config.i18n.raise_on_missing_translations = true
49 |
50 | # Annotate rendered view with file names.
51 | # config.action_view.annotate_rendered_view_with_filenames = true
52 |
53 | # Uncomment if you wish to allow Action Cable access from any origin.
54 | # config.action_cable.disable_request_forgery_protection = true
55 | end
56 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
6 | # Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) }
7 |
8 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code
9 | # by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'".
10 | Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"]
11 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Specify a serializer for the signed and encrypted cookie jars.
6 | # Valid options are :json, :marshal, and :hybrid.
7 | Rails.application.config.action_dispatch.cookies_serializer = :marshal
8 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Configure parameters to be filtered from the log file. Use this to limit dissemination of
6 | # sensitive information. See the ActiveSupport::ParameterFilter documentation for supported
7 | # notations and behaviors.
8 | Rails.application.config.filter_parameters += %i[
9 | passw secret token _key crypt salt certificate otp ssn
10 | ]
11 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | Rails.application.config.session_store :cookie_store, key: "_dummy_session"
6 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # This file contains settings for ActionController::ParamsWrapper which
6 | # is enabled by default.
7 |
8 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
9 | ActiveSupport.on_load(:action_controller) do
10 | wrap_parameters format: [:json]
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/config/routes.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Rails.application.routes.draw do
4 | # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
5 |
6 | mount DiasporaFederation::Engine => "/"
7 |
8 | get "discovery" => "discovery#discovery"
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/config/secrets.yml:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rake secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 |
13 | development:
14 | secret_key_base: 944b2cfb9fc44368fc73cdd7f5f09349f6a064c582f6352a179dfcb4d99cb62035304b3603b1fa3deb79d1de24c73ef1d8006e60e2a1cff2266b9ecca908a8f0
15 |
16 | test:
17 | secret_key_base: b5cc0bf00de1626234552283a86b3e6d629491ad64c2b51bc39ae57743aca373e9854b278650555ab14a1581223929798197ca8c069849528eafaff5caa48416
18 |
19 | # Do not keep production secrets in the repository,
20 | # instead read values from the environment.
21 | production:
22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
23 |
--------------------------------------------------------------------------------
/test/dummy/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diaspora/diaspora_federation/4468b8b8e111aaf4924e7f1431c8359788b116cf/test/dummy/log/.keep
--------------------------------------------------------------------------------
/test/scripts/ci.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -x
4 |
5 | if [[ ${BUNDLE_GEMFILE} =~ .*test/gemfiles/.*.Gemfile ]]; then
6 | if [[ ${BUNDLE_GEMFILE} =~ .*/no-rails.Gemfile ]]; then
7 | if grep activesupport "${BUNDLE_GEMFILE}.lock"; then
8 | echo "ERROR! no-rails.Gemfile.lock contains rails dependency!"
9 | exit 1
10 | fi
11 | fi
12 |
13 | # No coverage for other gemfiles, because some specs are disabled
14 | export NO_COVERAGE="true"
15 | bundle exec rake --trace
16 | else
17 | if [[ -n ${CC_TEST_REPORTER_ID} ]]; then
18 | curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
19 | chmod +x ./cc-test-reporter
20 | ./cc-test-reporter before-build
21 | fi
22 |
23 | bundle exec rake --trace
24 | test_exit_code=$?
25 |
26 | if [[ -n ${CC_TEST_REPORTER_ID} ]]; then
27 | ./cc-test-reporter after-build --exit-code ${test_exit_code}
28 | fi
29 |
30 | exit ${test_exit_code}
31 | fi
32 |
--------------------------------------------------------------------------------