Compare commits
2 Commits
v0.10.0
...
ba683a7b95
| Author | SHA1 | Date | |
|---|---|---|---|
|
ba683a7b95
|
|||
|
90a8a70c15
|
2
Gemfile
2
Gemfile
@@ -44,6 +44,8 @@ gem 'pagy', '~> 6.0', '>= 6.0.2'
|
||||
gem 'flipper'
|
||||
gem 'flipper-active_record'
|
||||
gem 'flipper-ui'
|
||||
gem 'gpgme', '~> 2.0.24'
|
||||
gem 'zbase32', '~> 0.1.1'
|
||||
|
||||
# HTTP requests
|
||||
gem 'faraday'
|
||||
|
||||
@@ -197,6 +197,8 @@ GEM
|
||||
raabro (~> 1.4)
|
||||
globalid (1.2.1)
|
||||
activesupport (>= 6.1)
|
||||
gpgme (2.0.24)
|
||||
mini_portile2 (~> 2.7)
|
||||
hashdiff (1.1.0)
|
||||
i18n (1.14.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
@@ -483,6 +485,7 @@ GEM
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
yard (0.9.34)
|
||||
zbase32 (0.1.1)
|
||||
zeitwerk (2.6.12)
|
||||
|
||||
PLATFORMS
|
||||
@@ -507,6 +510,7 @@ DEPENDENCIES
|
||||
flipper
|
||||
flipper-active_record
|
||||
flipper-ui
|
||||
gpgme (~> 2.0.24)
|
||||
image_processing (~> 1.12.2)
|
||||
importmap-rails
|
||||
jbuilder (~> 2.7)
|
||||
@@ -540,6 +544,7 @@ DEPENDENCIES
|
||||
warden
|
||||
web-console (~> 4.2)
|
||||
webmock
|
||||
zbase32 (~> 0.1.1)
|
||||
|
||||
BUNDLED WITH
|
||||
2.5.5
|
||||
|
||||
@@ -30,7 +30,7 @@ class Admin::UsersController < Admin::BaseController
|
||||
amount = params[:amount].to_i
|
||||
notify_user = ActiveRecord::Type::Boolean.new.cast(params[:notify_user])
|
||||
|
||||
CreateInvitations.call(user: @user, amount: amount, notify: notify_user)
|
||||
UserManager::CreateInvitations.call(user: @user, amount: amount, notify: notify_user)
|
||||
|
||||
redirect_to admin_user_path(@user.cn), flash: {
|
||||
success: "Added #{amount} invitations to #{@user.cn}'s account"
|
||||
|
||||
@@ -96,7 +96,7 @@ class SignupController < ApplicationController
|
||||
session[:new_user] = nil
|
||||
session[:validation_error] = nil
|
||||
|
||||
CreateAccount.call(account: {
|
||||
UserManager::CreateAccount.call(account: {
|
||||
username: @user.cn,
|
||||
domain: Setting.primary_domain,
|
||||
email: @user.email,
|
||||
|
||||
@@ -3,9 +3,10 @@ require 'nostr'
|
||||
class User < ApplicationRecord
|
||||
include EmailValidatable
|
||||
|
||||
attr_accessor :display_name
|
||||
attr_accessor :avatar_new
|
||||
attr_accessor :current_password
|
||||
attr_accessor :avatar_new
|
||||
attr_accessor :display_name
|
||||
attr_accessor :pgp_pubkey
|
||||
|
||||
serialize :preferences, coder: UserPreferences
|
||||
|
||||
@@ -51,6 +52,8 @@ class User < ApplicationRecord
|
||||
|
||||
validate :acceptable_avatar
|
||||
|
||||
validate :acceptable_pgp_key_format, if: -> { defined?(@pgp_pubkey) && @pgp_pubkey != "" }
|
||||
|
||||
#
|
||||
# Scopes
|
||||
#
|
||||
@@ -165,6 +168,23 @@ class User < ApplicationRecord
|
||||
Nostr::PublicKey.new(nostr_pubkey).to_bech32
|
||||
end
|
||||
|
||||
def pgp_pubkey
|
||||
@pgp_pubkey ||= ldap_entry[:pgp_key]
|
||||
end
|
||||
|
||||
def gnupg_key
|
||||
return nil unless pgp_pubkey.present?
|
||||
@gnupg_key ||= GPGME::Key.get(pgp_fpr)
|
||||
end
|
||||
|
||||
def pgp_pubkey_contains_user_address?
|
||||
gnupg_key.uids.map(&:email).include?(address)
|
||||
end
|
||||
|
||||
def wkd_hash
|
||||
ZBase32.encode(Digest::SHA1.digest(cn))
|
||||
end
|
||||
|
||||
def avatar
|
||||
@avatar_base64 ||= LdapManager::FetchAvatar.call(cn: cn)
|
||||
end
|
||||
@@ -214,4 +234,10 @@ class User < ApplicationRecord
|
||||
errors.add(:avatar, "must be a JPEG or PNG file")
|
||||
end
|
||||
end
|
||||
|
||||
def acceptable_pgp_key_format
|
||||
unless GPGME::Key.valid?(pgp_pubkey)
|
||||
errors.add(:pgp_pubkey, 'is not a valid armored PGP public key block')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
class CreateAccount < ApplicationService
|
||||
def initialize(account:)
|
||||
@username = account[:username]
|
||||
@domain = account[:ou] || Setting.primary_domain
|
||||
@email = account[:email]
|
||||
@password = account[:password]
|
||||
@invitation = account[:invitation]
|
||||
@confirmed = account[:confirmed]
|
||||
end
|
||||
|
||||
def call
|
||||
user = create_user_in_database
|
||||
add_ldap_document
|
||||
create_lndhub_account(user) if Setting.lndhub_enabled
|
||||
|
||||
if @invitation.present?
|
||||
update_invitation(user.id)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_user_in_database
|
||||
User.create!(
|
||||
cn: @username,
|
||||
ou: @domain,
|
||||
email: @email,
|
||||
password: @password,
|
||||
password_confirmation: @password,
|
||||
confirmed_at: @confirmed ? DateTime.now : nil
|
||||
)
|
||||
end
|
||||
|
||||
def update_invitation(user_id)
|
||||
@invitation.update! invited_user_id: user_id, used_at: DateTime.now
|
||||
end
|
||||
|
||||
def add_ldap_document
|
||||
hashed_pw = Devise.ldap_auth_password_builder.call(@password)
|
||||
CreateLdapUserJob.perform_later(
|
||||
username: @username,
|
||||
domain: @domain,
|
||||
email: @email,
|
||||
hashed_pw: hashed_pw,
|
||||
confirmed: @confirmed
|
||||
)
|
||||
end
|
||||
|
||||
def create_lndhub_account(user)
|
||||
#TODO enable in development when we have a local lndhub (mock?) API
|
||||
return if Rails.env.development?
|
||||
CreateLndhubAccountJob.perform_later(user)
|
||||
end
|
||||
end
|
||||
@@ -1,17 +0,0 @@
|
||||
class CreateInvitations < ApplicationService
|
||||
def initialize(user:, amount:, notify: true)
|
||||
@user = user
|
||||
@amount = amount
|
||||
@notify = notify
|
||||
end
|
||||
|
||||
def call
|
||||
@amount.times do
|
||||
Invitation.create(user: @user)
|
||||
end
|
||||
|
||||
if @notify
|
||||
NotificationMailer.with(user: @user).new_invitations_available.deliver_later
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -58,7 +58,7 @@ class LdapService < ApplicationService
|
||||
|
||||
attributes = %w[
|
||||
dn cn uid mail displayName admin serviceEnabled
|
||||
mailRoutingAddress mailpassword nostrKey
|
||||
mailRoutingAddress mailpassword nostrKey pgpKey
|
||||
]
|
||||
filter = Net::LDAP::Filter.eq("uid", args[:uid] || "*")
|
||||
|
||||
@@ -73,7 +73,8 @@ class LdapService < ApplicationService
|
||||
services_enabled: e.try(:serviceEnabled),
|
||||
email_maildrop: e.try(:mailRoutingAddress),
|
||||
email_password: e.try(:mailpassword),
|
||||
nostr_key: e.try(:nostrKey) ? e.nostrKey.first : nil
|
||||
nostr_key: e.try(:nostrKey) ? e.nostrKey.first : nil,
|
||||
pgp_key: e.try(:pgpKey) ? e.pgpKey.first : nil
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -101,7 +102,7 @@ class LdapService < ApplicationService
|
||||
dn = "ou=#{ou},cn=users,#{ldap_suffix}"
|
||||
|
||||
aci = <<-EOS
|
||||
(target="ldap:///cn=*,ou=#{ou},cn=users,#{ldap_suffix}")(targetattr="cn || sn || uid || userPassword || mail || mailRoutingAddress || serviceEnabled || nostrKey || nsRole || objectClass") (version 3.0; acl "service-#{ou.gsub(".", "-")}-read-search"; allow (read,search) userdn="ldap:///uid=service,ou=#{ou},cn=applications,#{ldap_suffix}";)
|
||||
(target="ldap:///cn=*,ou=#{ou},cn=users,#{ldap_suffix}")(targetattr="cn || sn || uid || userPassword || mail || mailRoutingAddress || serviceEnabled || nostrKey || pgpKey || nsRole || objectClass") (version 3.0; acl "service-#{ou.gsub(".", "-")}-read-search"; allow (read,search) userdn="ldap:///uid=service,ou=#{ou},cn=applications,#{ldap_suffix}";)
|
||||
EOS
|
||||
|
||||
attrs = {
|
||||
|
||||
56
app/services/user_manager/create_account.rb
Normal file
56
app/services/user_manager/create_account.rb
Normal file
@@ -0,0 +1,56 @@
|
||||
module UserManager
|
||||
class CreateAccount < UserManagerService
|
||||
def initialize(account:)
|
||||
@username = account[:username]
|
||||
@domain = account[:ou] || Setting.primary_domain
|
||||
@email = account[:email]
|
||||
@password = account[:password]
|
||||
@invitation = account[:invitation]
|
||||
@confirmed = account[:confirmed]
|
||||
end
|
||||
|
||||
def call
|
||||
user = create_user_in_database
|
||||
add_ldap_document
|
||||
create_lndhub_account(user) if Setting.lndhub_enabled
|
||||
|
||||
if @invitation.present?
|
||||
update_invitation(user.id)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_user_in_database
|
||||
User.create!(
|
||||
cn: @username,
|
||||
ou: @domain,
|
||||
email: @email,
|
||||
password: @password,
|
||||
password_confirmation: @password,
|
||||
confirmed_at: @confirmed ? DateTime.now : nil
|
||||
)
|
||||
end
|
||||
|
||||
def update_invitation(user_id)
|
||||
@invitation.update! invited_user_id: user_id, used_at: DateTime.now
|
||||
end
|
||||
|
||||
def add_ldap_document
|
||||
hashed_pw = Devise.ldap_auth_password_builder.call(@password)
|
||||
CreateLdapUserJob.perform_later(
|
||||
username: @username,
|
||||
domain: @domain,
|
||||
email: @email,
|
||||
hashed_pw: hashed_pw,
|
||||
confirmed: @confirmed
|
||||
)
|
||||
end
|
||||
|
||||
def create_lndhub_account(user)
|
||||
#TODO enable in development when we have a local lndhub (mock?) API
|
||||
return if Rails.env.development?
|
||||
CreateLndhubAccountJob.perform_later(user)
|
||||
end
|
||||
end
|
||||
end
|
||||
19
app/services/user_manager/create_invitations.rb
Normal file
19
app/services/user_manager/create_invitations.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
module UserManager
|
||||
class CreateInvitations < UserManagerService
|
||||
def initialize(user:, amount:, notify: true)
|
||||
@user = user
|
||||
@amount = amount
|
||||
@notify = notify
|
||||
end
|
||||
|
||||
def call
|
||||
@amount.times do
|
||||
Invitation.create(user: @user)
|
||||
end
|
||||
|
||||
if @notify
|
||||
NotificationMailer.with(user: @user).new_invitations_available.deliver_later
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
2
app/services/user_manager_service.rb
Normal file
2
app/services/user_manager_service.rb
Normal file
@@ -0,0 +1,2 @@
|
||||
class UserManagerService < ApplicationService
|
||||
end
|
||||
5
db/migrate/20240922205634_add_pgp_fpr_to_users.rb
Normal file
5
db/migrate/20240922205634_add_pgp_fpr_to_users.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
class AddPgpFprToUsers < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
add_column :users, :pgp_fpr, :string
|
||||
end
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.1].define(version: 2024_06_07_123654) do
|
||||
ActiveRecord::Schema[7.1].define(version: 2024_09_22_205634) do
|
||||
create_table "active_storage_attachments", force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.string "record_type", null: false
|
||||
@@ -132,6 +132,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_06_07_123654) do
|
||||
t.datetime "remember_created_at"
|
||||
t.string "remember_token"
|
||||
t.text "preferences"
|
||||
t.string "pgp_fpr"
|
||||
t.index ["email"], name: "index_users_on_email", unique: true
|
||||
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
|
||||
end
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace :ldap do
|
||||
|
||||
desc "Add custom attributes to schema"
|
||||
task add_custom_attributes: :environment do |t, args|
|
||||
%w[ admin service_enabled nostr_key ].each do |name|
|
||||
%w[ admin service_enabled nostr_key pgp_key ].each do |name|
|
||||
Rake::Task["ldap:modify_ldap_schema"].invoke(name, "add")
|
||||
Rake::Task['ldap:modify_ldap_schema'].reenable
|
||||
end
|
||||
@@ -29,7 +29,7 @@ namespace :ldap do
|
||||
|
||||
desc "Delete custom attributes from schema"
|
||||
task delete_custom_attributes: :environment do |t, args|
|
||||
%w[ admin service_enabled nostr_key ].each do |name|
|
||||
%w[ admin service_enabled nostr_key pgp_key ].each do |name|
|
||||
Rake::Task["ldap:modify_ldap_schema"].invoke(name, "delete")
|
||||
Rake::Task['ldap:modify_ldap_schema'].reenable
|
||||
end
|
||||
|
||||
8
schemas/ldap/pgp_key.ldif
Normal file
8
schemas/ldap/pgp_key.ldif
Normal file
@@ -0,0 +1,8 @@
|
||||
dn: cn=schema
|
||||
changetype: modify
|
||||
add: attributeTypes
|
||||
attributeTypes: ( 1.3.6.1.4.1.3401.8.2.11
|
||||
NAME 'pgpKey'
|
||||
DESC 'OpenPGP public key block'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
@@ -52,7 +52,7 @@ RSpec.describe "Signup", type: :feature do
|
||||
click_button "Continue"
|
||||
expect(page).to have_content("Choose a password")
|
||||
|
||||
expect(CreateAccount).to receive(:call)
|
||||
expect(UserManager::CreateAccount).to receive(:call)
|
||||
.with(account: {
|
||||
username: "tony", domain: "kosmos.org",
|
||||
email: "tony@example.com", password: "a-valid-password",
|
||||
@@ -96,7 +96,7 @@ RSpec.describe "Signup", type: :feature do
|
||||
click_button "Create account"
|
||||
expect(page).to have_content("Password is too short")
|
||||
|
||||
expect(CreateAccount).to receive(:call)
|
||||
expect(UserManager::CreateAccount).to receive(:call)
|
||||
.with(account: {
|
||||
username: "tony", domain: "kosmos.org",
|
||||
email: "tony@example.com", password: "a-valid-password",
|
||||
|
||||
11
spec/fixtures/files/pgp_key_invalid.asc
vendored
Normal file
11
spec/fixtures/files/pgp_key_invalid.asc
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
b7O1u120JkFsaWNlIExvdmVsYWNlIDxhbGljZUBvcGVucGdwLmV4YW1wbGU+iJAE
|
||||
ExYIADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQTrhbtfozp14V6UTmPy
|
||||
MVUMT0fjjgUCXaWfOgAKCRDyMVUMT0fjjukrAPoDnHBSogOmsHOsd9qGsiZpgRnO
|
||||
dypvbm+QtXZqth9rvwD9HcDC0tC+PHAsO7OTh1S1TC9RiJsvawAfCPaQZoed8gK4
|
||||
OARcRwTpEgorBgEEAZdVAQUBAQdAQv8GIa2rSTzgqbXCpDDYMiKRVitCsy203x3s
|
||||
E9+eviIDAQgHiHgEGBYIACAWIQTrhbtfozp14V6UTmPyMVUMT0fjjgUCXEcE6QIb
|
||||
DAAKCRDyMVUMT0fjjlnQAQDFHUs6TIcxrNTtEZFjUFm1M0PJ1Dng/cDW4xN80fsn
|
||||
0QEA22Kr7VkCjeAEC08VSTeV+QFsmz55/lntWkwYWhmvOgE=
|
||||
=iIGO
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
16
spec/fixtures/files/pgp_key_valid_alice.asc
vendored
Normal file
16
spec/fixtures/files/pgp_key_valid_alice.asc
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Comment: Alice's OpenPGP certificate
|
||||
Comment: https://www.ietf.org/id/draft-bre-openpgp-samples-01.html
|
||||
|
||||
mDMEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U
|
||||
b7O1u120JkFsaWNlIExvdmVsYWNlIDxhbGljZUBvcGVucGdwLmV4YW1wbGU+iJAE
|
||||
ExYIADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQTrhbtfozp14V6UTmPy
|
||||
MVUMT0fjjgUCXaWfOgAKCRDyMVUMT0fjjukrAPoDnHBSogOmsHOsd9qGsiZpgRnO
|
||||
dypvbm+QtXZqth9rvwD9HcDC0tC+PHAsO7OTh1S1TC9RiJsvawAfCPaQZoed8gK4
|
||||
OARcRwTpEgorBgEEAZdVAQUBAQdAQv8GIa2rSTzgqbXCpDDYMiKRVitCsy203x3s
|
||||
E9+eviIDAQgHiHgEGBYIACAWIQTrhbtfozp14V6UTmPyMVUMT0fjjgUCXEcE6QIb
|
||||
DAAKCRDyMVUMT0fjjlnQAQDFHUs6TIcxrNTtEZFjUFm1M0PJ1Dng/cDW4xN80fsn
|
||||
0QEA22Kr7VkCjeAEC08VSTeV+QFsmz55/lntWkwYWhmvOgE=
|
||||
=iIGO
|
||||
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
13
spec/fixtures/files/pgp_key_valid_jimmy.asc
vendored
Normal file
13
spec/fixtures/files/pgp_key_valid_jimmy.asc
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEZvFjRhYJKwYBBAHaRw8BAQdACUxVX9bGlbuNR0MNYUyHHxTcOgm4qjwq8Bjg
|
||||
7P41OFK0GEppbW15IDxqaW1teUBrb3Ntb3Mub3JnPoiZBBMWCgBBFiEEMWv1FiNt
|
||||
r3cjaxX2BX2Tly+4YsMFAmbxY0YCGwMFCQWjmoAFCwkIBwICIgIGFQoJCAsCBBYC
|
||||
AwECHgcCF4AACgkQBX2Tly+4YsMjHgEAoOOLrv9pWbi8hhrSMkqJ7FJvsBTQF//U
|
||||
aJUQRa8CTgoBAI3kyGKZ8gOC8UOOKsUC0LiNCVXPyX45h8T4QFRdEVYKuDgEZvFj
|
||||
RhIKKwYBBAGXVQEFAQEHQIomqcQ59UjtQex54pz8qGqyxCj2DPJYUat9pXinDgN8
|
||||
AwEIB4h+BBgWCgAmFiEEMWv1FiNtr3cjaxX2BX2Tly+4YsMFAmbxY0YCGwwFCQWj
|
||||
moAACgkQBX2Tly+4YsPoVgEA/9Q5Gs1klP4u/nw343V57e9s4RKmEiRSkErnC9wW
|
||||
Iu0A/jp6Elz2pDQPB2XLwcb+n7JlgA05HI0zWj1+EoM7TC4J
|
||||
=KQbn
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
@@ -1,20 +1,16 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe User, type: :model do
|
||||
let(:user) { create :user, cn: "philipp" }
|
||||
let(:user) { create :user, cn: "philipp", ou: "kosmos.org", email: "philipp@example.com" }
|
||||
let(:dn) { "cn=philipp,ou=kosmos.org,cn=users,dc=kosmos,dc=org" }
|
||||
|
||||
describe "#address" do
|
||||
let(:user) { build :user, cn: "jimmy", ou: "kosmos.org" }
|
||||
|
||||
it "returns the user address" do
|
||||
expect(user.address).to eq("jimmy@kosmos.org")
|
||||
expect(user.address).to eq("philipp@kosmos.org")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#mastodon_address" do
|
||||
let(:user) { build :user, cn: "jimmy", ou: "kosmos.org" }
|
||||
|
||||
context "Mastodon service not configured" do
|
||||
before do
|
||||
Setting.mastodon_enabled = false
|
||||
@@ -32,7 +28,7 @@ RSpec.describe User, type: :model do
|
||||
|
||||
describe "domain is the same as primary domain" do
|
||||
it "returns the user address" do
|
||||
expect(user.mastodon_address).to eq("jimmy@kosmos.org")
|
||||
expect(user.mastodon_address).to eq("philipp@kosmos.org")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -42,7 +38,7 @@ RSpec.describe User, type: :model do
|
||||
end
|
||||
|
||||
it "returns the user address" do
|
||||
expect(user.mastodon_address).to eq("jimmy@kosmos.social")
|
||||
expect(user.mastodon_address).to eq("philipp@kosmos.social")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -239,7 +235,7 @@ RSpec.describe User, type: :model do
|
||||
|
||||
describe "#nostr_pubkey" do
|
||||
before do
|
||||
allow_any_instance_of(User).to receive(:ldap_entry)
|
||||
allow(user).to receive(:ldap_entry)
|
||||
.and_return({ nostr_key: "07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3" })
|
||||
end
|
||||
|
||||
@@ -250,7 +246,7 @@ RSpec.describe User, type: :model do
|
||||
|
||||
describe "#nostr_pubkey_bech32" do
|
||||
before do
|
||||
allow_any_instance_of(User).to receive(:ldap_entry)
|
||||
allow(user).to receive(:ldap_entry)
|
||||
.and_return({ nostr_key: "07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3" })
|
||||
end
|
||||
|
||||
@@ -258,4 +254,74 @@ RSpec.describe User, type: :model do
|
||||
expect(user.nostr_pubkey_bech32).to eq("npub1qlsc3g0lsl8pw8230w8d9wm6xxcax3f6pkemz5measrmwfxjxteslf2hac")
|
||||
end
|
||||
end
|
||||
|
||||
describe "OpenPGP key" do
|
||||
let(:alice) { create :user, id: 2, cn: "alice", email: "alice@example.com" }
|
||||
let(:jimmy) { create :user, id: 3, cn: "jimmy", email: "jimmy@example.com" }
|
||||
let(:valid_key_alice) { File.read("#{Rails.root}/spec/fixtures/files/pgp_key_valid_alice.asc") }
|
||||
let(:valid_key_jimmy) { File.read("#{Rails.root}/spec/fixtures/files/pgp_key_valid_jimmy.asc") }
|
||||
let(:fingerprint_alice) { "EB85BB5FA33A75E15E944E63F231550C4F47E38E" }
|
||||
let(:fingerprint_jimmy) { "316BF516236DAF77236B15F6057D93972FB862C3" }
|
||||
let(:gnupg_key_alice) { }
|
||||
let(:invalid_key) { File.read("#{Rails.root}/spec/fixtures/files/pgp_key_invalid.asc") }
|
||||
|
||||
before do
|
||||
GPGME::Key.import(valid_key_alice)
|
||||
GPGME::Key.import(valid_key_jimmy)
|
||||
alice.update pgp_fpr: fingerprint_alice
|
||||
jimmy.update pgp_fpr: fingerprint_jimmy
|
||||
allow(alice).to receive(:ldap_entry).and_return({ pgp_key: valid_key_alice })
|
||||
allow(jimmy).to receive(:ldap_entry).and_return({ pgp_key: valid_key_jimmy })
|
||||
end
|
||||
|
||||
after do
|
||||
GPGME::Key.get(fingerprint_alice).delete!
|
||||
GPGME::Key.get(fingerprint_jimmy).delete!
|
||||
end
|
||||
|
||||
describe "#acceptable_pgp_key_format" do
|
||||
it "validates the record when the key is valid" do
|
||||
alice.pgp_pubkey = valid_key_alice
|
||||
expect(alice).to be_valid
|
||||
end
|
||||
|
||||
it "adds a validation error when the key is not valid" do
|
||||
user.pgp_pubkey = invalid_key
|
||||
expect(user).to_not be_valid
|
||||
expect(user.errors[:pgp_pubkey]).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
describe "#pgp_pubkey" do
|
||||
it "returns the raw pubkey from LDAP" do
|
||||
expect(alice.pgp_pubkey).to eq(valid_key_alice)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#gnupg_key" do
|
||||
subject { alice.gnupg_key }
|
||||
|
||||
it "returns a GPGME::Key object from the system's GPG keyring" do
|
||||
expect(subject).to be_a(GPGME::Key)
|
||||
expect(subject.fingerprint).to eq(fingerprint_alice)
|
||||
expect(subject.email).to eq("alice@openpgp.example")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#pgp_pubkey_contains_user_address?" do
|
||||
it "returns false when the user address is one of the UIDs of the key" do
|
||||
expect(alice.pgp_pubkey_contains_user_address?).to eq(false)
|
||||
end
|
||||
|
||||
it "returns true when the user address is missing from the UIDs of the key" do
|
||||
expect(jimmy.pgp_pubkey_contains_user_address?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe "wkd_hash" do
|
||||
it "returns a z-base32 encoded SHA-1 digest of the username" do
|
||||
expect(alice.wkd_hash).to eq("kei1q4tipxxu1yj79k9kfukdhfy631xe")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe CreateAccount, type: :model do
|
||||
RSpec.describe UserManager::CreateAccount, type: :model do
|
||||
describe "#create_user_in_database" do
|
||||
let(:service) { CreateAccount.new(account: {
|
||||
let(:service) { described_class.new(account: {
|
||||
username: 'isaacnewton',
|
||||
email: 'isaacnewton@example.com',
|
||||
password: 'bright-ideas-in-autumn'
|
||||
@@ -19,7 +19,7 @@ RSpec.describe CreateAccount, type: :model do
|
||||
|
||||
describe "#update_invitation" do
|
||||
let(:invitation) { create :invitation }
|
||||
let(:service) { CreateAccount.new(account: {
|
||||
let(:service) { described_class.new(account: {
|
||||
username: 'isaacnewton',
|
||||
email: 'isaacnewton@example.com',
|
||||
password: 'bright-ideas-in-autumn',
|
||||
@@ -42,7 +42,7 @@ RSpec.describe CreateAccount, type: :model do
|
||||
describe "#add_ldap_document" do
|
||||
include ActiveJob::TestHelper
|
||||
|
||||
let(:service) { CreateAccount.new(account: {
|
||||
let(:service) { described_class.new(account: {
|
||||
username: 'halfinney',
|
||||
email: 'halfinney@example.com',
|
||||
password: 'remember-remember-the-5th-of-november'
|
||||
@@ -68,7 +68,7 @@ RSpec.describe CreateAccount, type: :model do
|
||||
describe "#add_ldap_document for pre-confirmed account" do
|
||||
include ActiveJob::TestHelper
|
||||
|
||||
let(:service) { CreateAccount.new(account: {
|
||||
let(:service) { described_class.new(account: {
|
||||
username: 'halfinney',
|
||||
email: 'halfinney@example.com',
|
||||
password: 'remember-remember-the-5th-of-november',
|
||||
@@ -89,7 +89,7 @@ RSpec.describe CreateAccount, type: :model do
|
||||
describe "#create_lndhub_account" do
|
||||
include ActiveJob::TestHelper
|
||||
|
||||
let(:service) { CreateAccount.new(account: {
|
||||
let(:service) { described_class.new(account: {
|
||||
username: 'halfinney', email: 'halfinney@example.com',
|
||||
password: 'bright-ideas-in-winter'
|
||||
})}
|
||||
@@ -1,13 +1,13 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe CreateInvitations, type: :model do
|
||||
RSpec.describe UserManager::CreateInvitations, type: :model do
|
||||
include ActiveJob::TestHelper
|
||||
|
||||
let(:user) { create :user }
|
||||
|
||||
describe "#call" do
|
||||
before do
|
||||
CreateInvitations.call(user: user, amount: 5)
|
||||
described_class.call(user: user, amount: 5)
|
||||
end
|
||||
|
||||
after(:each) { clear_enqueued_jobs }
|
||||
@@ -28,7 +28,7 @@ RSpec.describe CreateInvitations, type: :model do
|
||||
|
||||
describe "#call with notification disabled" do
|
||||
before do
|
||||
CreateInvitations.call(user: user, amount: 3, notify: false)
|
||||
described_class.call(user: user, amount: 3, notify: false)
|
||||
end
|
||||
|
||||
after(:each) { clear_enqueued_jobs }
|
||||
Reference in New Issue
Block a user