26 Commits

Author SHA1 Message Date
raucao 78ecef80dc WIP: Import deno modules for use with import maps
continuous-integration/drone/push Build is passing
2024-10-09 15:17:35 +02:00
raucao 64de4deddd Fix serviceEnabled indicator on admin page
continuous-integration/drone/push Build is passing
2024-09-24 21:38:01 +02:00
raucao 8f7994d82e 0.10.0
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is passing
2024-09-18 15:49:07 +02:00
raucao a7d0e71ab6 Fix spec
continuous-integration/drone/push Build is passing
2024-09-18 14:46:46 +02:00
raucao 27d9f73c61 Set host for RS auth url
continuous-integration/drone/push Build is failing
With X-Forwarded-Host set on the proxied request, Rails uses that host
for URLs. But we need it to be the accounts domain.
2024-09-14 17:17:09 +02:00
raucao ed3de8b16f Allow CORS for all LNURL endpoints
continuous-integration/drone/push Build is passing
2024-09-14 16:46:14 +02:00
raucao d7b4c67953 Fix config when set to empty string
continuous-integration/drone/push Build is passing
2024-09-14 16:40:22 +02:00
greg 7489d4a32f Merge pull request 'Add config for separate primary domain Nostr pubkey' (#204) from feature/nostr_pubkey_primary_domain into master
continuous-integration/drone/push Build is passing
Reviewed-on: #204
Reviewed-by: Greg <greg@noreply.kosmos.org>
2024-09-13 12:33:11 +00:00
raucao ac77e5b7c1 Allow ENV var for new setting
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 5s
2024-09-11 16:31:04 +02:00
raucao e544c28105 Config for separate primary domain Nostr pubkey
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Allow to configure a separate key for the NIP-05 address of the primary
domain vs the accounts domain.
2024-09-11 16:28:12 +02:00
raucao 4909dac5c2 Fix typo
continuous-integration/drone/push Build is passing
The return value of `strip!` is `nil`
2024-09-11 16:26:48 +02:00
raucao 3cf4348695 Merge pull request 'Make default user services configurable by admins' (#203) from feature/default_service_settings into master
continuous-integration/drone/push Build is passing
Reviewed-on: #203
Reviewed-by: galfert <garret.alfert@gmail.com>
2024-09-11 11:21:38 +00:00
raucao af3da0a26c Set CORS headers for all .well-known responses
continuous-integration/drone/push Build is passing
So we don't have to consider it for reverse proxies etc.
2024-09-10 16:06:11 +02:00
raucao 2d32320c7d Style check boxes
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 5s
2024-09-05 11:24:38 +02:00
raucao fc2bec6246 Make default user services configurable by admin
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-09-05 11:11:32 +02:00
raucao 5addd25186 Add service details config, use for known services 2024-09-05 11:10:54 +02:00
raucao 215d178e69 Remove empty spec files 2024-09-05 11:10:10 +02:00
raucao 5474bf66e7 Turn default services into a configurable setting
With the default value being all enabled services
2024-09-04 13:06:32 +02:00
raucao ef2a37e2bf Sort user services in LDAP entry
Makes it predictable for programmatic comparisons (e.g. tests)
2024-09-04 13:05:36 +02:00
raucao 0e3180602c Rename "xmpp" user service back to "ejabberd"
If we ever add support for others, we can combine them as "xmpp" in
helper methods
2024-09-04 13:03:45 +02:00
raucao 15e2f9b962 Remove "in development" note
continuous-integration/drone/push Build is passing
2024-08-28 14:55:34 +02:00
raucao 4ae10c9b53 Refactor settings model
continuous-integration/drone/push Build is passing
Move the various sections to their own concerns, so they're easier to
find and maintain
2024-08-28 14:39:08 +02:00
raucao 45137e0cfe Merge pull request 'Fix Ruby issue on Apple silicon (without compiling a patched Ruby)' (#201) from chore/update_docker_image into master
continuous-integration/drone/push Build is passing
Reviewed-on: #201
Reviewed-by: galfert <garret.alfert@gmail.com>
2024-08-28 08:12:31 +00:00
raucao 717fe93104 Fix spec
continuous-integration/drone/push Build is passing
2024-08-22 14:07:54 +02:00
raucao e08ea64f47 Update Docker base image
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 5s
Fixes the bug with Ruby on Apple silicon
2024-08-12 10:34:02 +02:00
raucao 8cc2c9554f Revert "Fix Ruby in Docker container on Apple silicon"
This reverts commit bbf3fb91a0.
2024-08-12 10:15:18 +02:00
55 changed files with 986 additions and 307 deletions
+1
View File
@@ -0,0 +1 @@
@jsr:registry=https://npm.jsr.io
+4 -11
View File
@@ -1,24 +1,17 @@
# syntax=docker/dockerfile:1
FROM debian:bullseye-slim as base
FROM ruby:3.3.4
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# TODO Remove when upstream Ruby works properly on Apple silicon
RUN apt update && apt install -y build-essential wget autoconf libpq-dev pkg-config
RUN wget https://github.com/postmodern/ruby-install/releases/download/v0.9.3/ruby-install-0.9.3.tar.gz \
&& tar -xzvf ruby-install-0.9.3.tar.gz \
&& cd ruby-install-0.9.3/ \
&& make install
RUN ruby-install -p https://github.com/ruby/ruby/pull/9371.diff ruby 3.3.0
ENV PATH="/opt/rubies/ruby-3.3.0/bin:${PATH}"
RUN apt-get update -qq && apt-get install -y --no-install-recommends curl \
ldap-utils tini libvips
RUN apt-get install -y --no-install-recommends curl ldap-utils tini libvips
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
RUN apt-get update && apt-get install -y nodejs
WORKDIR /akkounts
COPY ["Gemfile", "Gemfile.lock", "package.json", "./"]
COPY ["Gemfile", "Gemfile.lock", "package.json", "yarn.lock", "./"]
RUN bundle install
RUN gem install foreman
+1 -1
View File
@@ -542,4 +542,4 @@ DEPENDENCIES
webmock
BUNDLED WITH
2.5.5
2.5.11
@@ -9,4 +9,12 @@ class Admin::Settings::RegistrationsController < Admin::SettingsController
success: "Settings saved"
}
end
private
def setting_params
params.require(:setting).permit([
:reserved_usernames, default_services: []
])
end
end
+13 -4
View File
@@ -9,11 +9,12 @@ class Admin::SettingsController < Admin::BaseController
changed_keys = []
setting_params.keys.each do |key|
next if setting_params[key].nil? ||
(Setting.send(key).to_s == setting_params[key].strip)
next if clean_param(key).nil? ||
(Setting.send(key).to_s == clean_param(key))
changed_keys.push(key)
setting = Setting.new(var: key)
setting.value = setting_params[key].strip
setting.value = clean_param(key)
unless setting.valid?
@errors.merge!(setting.errors)
end
@@ -24,7 +25,7 @@ class Admin::SettingsController < Admin::BaseController
end
changed_keys.each do |key|
Setting.send("#{key}=", setting_params[key].strip)
Setting.send("#{key}=", clean_param(key))
end
end
@@ -37,4 +38,12 @@ class Admin::SettingsController < Admin::BaseController
def setting_params
params.require(:setting).permit(Setting.editable_keys.map(&:to_sym))
end
def clean_param(key)
if Setting.get_field(key)[:type] == :string
setting_params[key].strip
else
setting_params[key]
end
end
end
+1 -1
View File
@@ -1,7 +1,7 @@
class LnurlpayController < ApplicationController
before_action :check_service_available
before_action :find_user
before_action :set_cors_access_control_headers, only: [:invoice]
before_action :set_cors_access_control_headers
MIN_SATS = 10
MAX_SATS = 1_000_000
+1 -1
View File
@@ -3,7 +3,7 @@ class Services::ChatController < Services::BaseController
before_action :require_service_available
def show
@service_enabled = current_user.service_enabled?(:xmpp)
@service_enabled = current_user.service_enabled?(:ejabberd)
end
private
+2 -10
View File
@@ -1,8 +1,6 @@
class WebfingerController < ApplicationController
class WebfingerController < WellKnownController
before_action :allow_cross_origin_requests, only: [:show]
layout false
def show
resource = params[:resource]
@@ -76,7 +74,7 @@ class WebfingerController < ApplicationController
end
def remotestorage_link
auth_url = new_rs_oauth_url(@username)
auth_url = new_rs_oauth_url(@username, host: Setting.accounts_domain)
storage_url = "#{Setting.rs_storage_url}/#{@username}"
{
@@ -91,10 +89,4 @@ class WebfingerController < ApplicationController
}
}
end
def allow_cross_origin_requests
return unless Rails.env.development?
headers['Access-Control-Allow-Origin'] = "*"
headers['Access-Control-Allow-Methods'] = "GET"
end
end
+14
View File
@@ -1,5 +1,8 @@
class WellKnownController < ApplicationController
before_action :require_nostr_enabled, only: [ :nostr ]
before_action :allow_cross_origin_requests, only: [ :nostr ]
layout false
def nostr
http_status :unprocessable_entity and return if params[:name].blank?
@@ -7,8 +10,14 @@ class WellKnownController < ApplicationController
relay_url = Setting.nostr_relay_url.presence
if params[:name] == "_"
if domain == Setting.primary_domain
# pubkey for the primary domain without a username (e.g. kosmos.org)
res = { names: { "_": Setting.nostr_public_key_primary_domain.presence || Setting.nostr_public_key } }
else
# pubkey for the akkounts domain without a username (e.g. accounts.kosmos.org)
res = { names: { "_": Setting.nostr_public_key } }
end
res[:relays] = { "_" => [ relay_url ] } if relay_url
else
@user = User.where(cn: params[:name], ou: domain).first
@@ -30,4 +39,9 @@ class WellKnownController < ApplicationController
def require_nostr_enabled
http_status :not_found unless Setting.nostr_enabled?
end
def allow_cross_origin_requests
headers['Access-Control-Allow-Origin'] = "*"
headers['Access-Control-Allow-Methods'] = "GET"
end
end
-2
View File
@@ -1,2 +0,0 @@
module DashboardHelper
end
-2
View File
@@ -1,2 +0,0 @@
module DonationsHelper
end
-2
View File
@@ -1,2 +0,0 @@
module InvitationsHelper
end
-2
View File
@@ -1,2 +0,0 @@
module LnurlpayHelper
end
+12
View File
@@ -0,0 +1,12 @@
module ServicesHelper
def service_human_name(key, category = :external)
SERVICES[category][key][:name] || key.to_s
end
def service_display_name(key, category = :external)
SERVICES[category][key][:display_name] ||
service_human_name(key, category)
end
end
-2
View File
@@ -1,2 +0,0 @@
module SettingsHelper
end
-2
View File
@@ -1,2 +0,0 @@
module SignupHelper
end
-2
View File
@@ -1,2 +0,0 @@
module UsersHelper
end
-2
View File
@@ -1,2 +0,0 @@
module WalletHelper
end
-2
View File
@@ -1,2 +0,0 @@
module WelcomeHelper
end
@@ -1,4 +1,5 @@
import { Controller } from "@hotwired/stimulus"
// import { Nostrify } from '@nostrify/nostrify';
// Connects to data-controller="nostr-login"
export default class extends Controller {
@@ -6,6 +7,9 @@ export default class extends Controller {
static values = { site: String, sharedSecret: String }
connect() {
// window.Nostrify = Nostrify;
// console.log(Nostrify);
if (window.nostr) {
this.loginButtonTarget.disabled = false
this.loginFormTarget.classList.remove("hidden")
+2 -2
View File
@@ -2,8 +2,8 @@ class XmppExchangeContactsJob < ApplicationJob
queue_as :default
def perform(inviter, invitee)
return unless inviter.service_enabled?(:xmpp) &&
invitee.service_enabled?(:xmpp) &&
return unless inviter.service_enabled?(:ejabberd) &&
invitee.service_enabled?(:ejabberd) &&
inviter.preferences[:xmpp_exchange_contacts_with_invitees]
ejabberd = EjabberdApiClient.new
@@ -0,0 +1,24 @@
module Settings
module BtcpaySettings
extend ActiveSupport::Concern
included do
field :btcpay_api_url, type: :string,
default: ENV["BTCPAY_API_URL"].presence
field :btcpay_enabled, type: :boolean,
default: ENV["BTCPAY_API_URL"].present?
field :btcpay_public_url, type: :string,
default: ENV["BTCPAY_PUBLIC_URL"].presence
field :btcpay_store_id, type: :string,
default: ENV["BTCPAY_STORE_ID"].presence
field :btcpay_auth_token, type: :string,
default: ENV["BTCPAY_AUTH_TOKEN"].presence
field :btcpay_publish_wallet_balances, type: :boolean, default: true
end
end
end
@@ -0,0 +1,16 @@
module Settings
module DiscourseSettings
extend ActiveSupport::Concern
included do
field :discourse_public_url, type: :string,
default: ENV["DISCOURSE_PUBLIC_URL"].presence
field :discourse_enabled, type: :boolean,
default: ENV["DISCOURSE_PUBLIC_URL"].present?
field :discourse_connect_secret, type: :string,
default: ENV["DISCOURSE_CONNECT_SECRET"].presence
end
end
end
@@ -0,0 +1,13 @@
module Settings
module DroneCiSettings
extend ActiveSupport::Concern
included do
field :droneci_public_url, type: :string,
default: ENV["DRONECI_PUBLIC_URL"].presence
field :droneci_enabled, type: :boolean,
default: ENV["DRONECI_PUBLIC_URL"].present?
end
end
end
@@ -0,0 +1,19 @@
module Settings
module EjabberdSettings
extend ActiveSupport::Concern
included do
field :ejabberd_enabled, type: :boolean,
default: ENV["EJABBERD_API_URL"].present?
field :ejabberd_api_url, type: :string,
default: ENV["EJABBERD_API_URL"].presence
field :ejabberd_admin_url, type: :string,
default: ENV["EJABBERD_ADMIN_URL"].presence
field :ejabberd_buddy_roster, type: :string,
default: "Buddies"
end
end
end
@@ -0,0 +1,28 @@
module Settings
module EmailSettings
extend ActiveSupport::Concern
included do
field :email_enabled, type: :boolean,
default: ENV["EMAIL_SMTP_HOST"].present?
# field :email_smtp_host, type: :string,
# default: ENV["EMAIL_SMTP_HOST"].presence
#
# field :email_smtp_port, type: :string,
# default: ENV["EMAIL_SMTP_PORT"].presence || 587
#
# field :email_smtp_enable_starttls, type: :string,
# default: ENV["EMAIL_SMTP_PORT"].presence || true
#
# field :email_auth_method, type: :string,
# default: ENV["EMAIL_AUTH_METHOD"].presence || "plain"
#
# field :email_imap_host, type: :string,
# default: ENV["EMAIL_IMAP_HOST"].presence
#
# field :email_imap_port, type: :string,
# default: ENV["EMAIL_IMAP_PORT"].presence || 993
end
end
end
@@ -0,0 +1,34 @@
module Settings
module GeneralSettings
extend ActiveSupport::Concern
included do
field :primary_domain, type: :string,
default: ENV["PRIMARY_DOMAIN"].presence
field :accounts_domain, type: :string,
default: ENV["AKKOUNTS_DOMAIN"].presence
#
# Internal services
#
field :redis_url, type: :string,
default: ENV["REDIS_URL"] || "redis://localhost:6379/0"
field :s3_enabled, type: :boolean,
default: ENV["S3_ENABLED"] && ENV["S3_ENABLED"].to_s != "false"
field :sentry_enabled, type: :boolean, readonly: true,
default: ENV["SENTRY_DSN"].present?
#
# Registrations
#
field :reserved_usernames, type: :array, default: %w[
account accounts donations mail webmaster support
]
end
end
end
@@ -0,0 +1,13 @@
module Settings
module GiteaSettings
extend ActiveSupport::Concern
included do
field :gitea_public_url, type: :string,
default: ENV["GITEA_PUBLIC_URL"].presence
field :gitea_enabled, type: :boolean,
default: ENV["GITEA_PUBLIC_URL"].present?
end
end
end
@@ -0,0 +1,25 @@
module Settings
module LightningNetworkSettings
extend ActiveSupport::Concern
included do
field :lndhub_api_url, type: :string,
default: ENV["LNDHUB_API_URL"].presence
field :lndhub_enabled, type: :boolean,
default: ENV["LNDHUB_API_URL"].present?
field :lndhub_admin_token, type: :string,
default: ENV["LNDHUB_ADMIN_TOKEN"].presence
field :lndhub_admin_enabled, type: :boolean,
default: ENV["LNDHUB_ADMIN_UI"] || false
field :lndhub_public_key, type: :string,
default: (ENV["LNDHUB_PUBLIC_KEY"] || "")
field :lndhub_keysend_enabled, type: :boolean,
default: -> { self.lndhub_public_key.present? }
end
end
end
@@ -0,0 +1,16 @@
module Settings
module MastodonSettings
extend ActiveSupport::Concern
included do
field :mastodon_public_url, type: :string,
default: ENV["MASTODON_PUBLIC_URL"].presence
field :mastodon_enabled, type: :boolean,
default: ENV["MASTODON_PUBLIC_URL"].present?
field :mastodon_address_domain, type: :string,
default: ENV["MASTODON_ADDRESS_DOMAIN"].presence || self.primary_domain
end
end
end
@@ -0,0 +1,13 @@
module Settings
module MediaWikiSettings
extend ActiveSupport::Concern
included do
field :mediawiki_public_url, type: :string,
default: ENV["MEDIAWIKI_PUBLIC_URL"].presence
field :mediawiki_enabled, type: :boolean,
default: ENV["MEDIAWIKI_PUBLIC_URL"].present?
end
end
end
@@ -0,0 +1,25 @@
module Settings
module NostrSettings
extend ActiveSupport::Concern
included do
field :nostr_enabled, type: :boolean,
default: ENV["NOSTR_PRIVATE_KEY"].present?
field :nostr_private_key, type: :string,
default: ENV["NOSTR_PRIVATE_KEY"].presence
field :nostr_public_key, type: :string,
default: ENV["NOSTR_PUBLIC_KEY"].presence
field :nostr_public_key_primary_domain, type: :string,
default: ENV["NOSTR_PUBLIC_KEY_PRIMARY_DOMAIN"].presence
field :nostr_relay_url, type: :string,
default: ENV["NOSTR_RELAY_URL"].presence
field :nostr_zaps_relay_limit, type: :integer,
default: 12
end
end
end
@@ -0,0 +1,9 @@
module Settings
module OpenCollectiveSettings
extend ActiveSupport::Concern
included do
field :opencollective_enabled, type: :boolean, default: true
end
end
end
@@ -0,0 +1,16 @@
module Settings
module RemoteStorageSettings
extend ActiveSupport::Concern
included do
field :remotestorage_enabled, type: :boolean,
default: ENV["RS_STORAGE_URL"].present?
field :rs_storage_url, type: :string,
default: ENV["RS_STORAGE_URL"].presence
field :rs_redis_url, type: :string,
default: ENV["RS_REDIS_URL"] || "redis://localhost:6379/1"
end
end
end
@@ -0,0 +1,11 @@
module Settings
module XmppSettings
extend ActiveSupport::Concern
included do
field :xmpp_default_rooms, type: :array, default: []
field :xmpp_autojoin_default_rooms, type: :boolean, default: false
field :xmpp_notifications_from_address, type: :string, default: primary_domain
end
end
end
+25 -221
View File
@@ -2,226 +2,30 @@
class Setting < RailsSettings::Base
cache_prefix { "v1" }
field :primary_domain, type: :string,
default: ENV["PRIMARY_DOMAIN"].presence
field :accounts_domain, type: :string,
default: ENV["AKKOUNTS_DOMAIN"].presence
#
# Internal services
#
field :redis_url, type: :string,
default: ENV["REDIS_URL"] || "redis://localhost:6379/0"
field :s3_enabled, type: :boolean,
default: ENV["S3_ENABLED"] && ENV["S3_ENABLED"].to_s != "false"
#
# Registrations
#
field :reserved_usernames, type: :array, default: %w[
account accounts donations mail webmaster support
]
#
# XMPP
#
field :xmpp_default_rooms, type: :array, default: []
field :xmpp_autojoin_default_rooms, type: :boolean, default: false
field :xmpp_notifications_from_address, type: :string, default: primary_domain
#
# Sentry
#
field :sentry_enabled, type: :boolean, readonly: true,
default: ENV["SENTRY_DSN"].present?
#
# BTCPay Server
#
field :btcpay_api_url, type: :string,
default: ENV["BTCPAY_API_URL"].presence
field :btcpay_enabled, type: :boolean,
default: ENV["BTCPAY_API_URL"].present?
field :btcpay_public_url, type: :string,
default: ENV["BTCPAY_PUBLIC_URL"].presence
field :btcpay_store_id, type: :string,
default: ENV["BTCPAY_STORE_ID"].presence
field :btcpay_auth_token, type: :string,
default: ENV["BTCPAY_AUTH_TOKEN"].presence
field :btcpay_publish_wallet_balances, type: :boolean, default: true
#
# Discourse
#
field :discourse_public_url, type: :string,
default: ENV["DISCOURSE_PUBLIC_URL"].presence
field :discourse_enabled, type: :boolean,
default: ENV["DISCOURSE_PUBLIC_URL"].present?
field :discourse_connect_secret, type: :string,
default: ENV["DISCOURSE_CONNECT_SECRET"].presence
#
# Drone CI
#
field :droneci_public_url, type: :string,
default: ENV["DRONECI_PUBLIC_URL"].presence
field :droneci_enabled, type: :boolean,
default: ENV["DRONECI_PUBLIC_URL"].present?
#
# ejabberd
#
field :ejabberd_enabled, type: :boolean,
default: ENV["EJABBERD_API_URL"].present?
field :ejabberd_api_url, type: :string,
default: ENV["EJABBERD_API_URL"].presence
field :ejabberd_admin_url, type: :string,
default: ENV["EJABBERD_ADMIN_URL"].presence
field :ejabberd_buddy_roster, type: :string,
default: "Buddies"
#
# Gitea
#
field :gitea_public_url, type: :string,
default: ENV["GITEA_PUBLIC_URL"].presence
field :gitea_enabled, type: :boolean,
default: ENV["GITEA_PUBLIC_URL"].present?
#
# Lightning Network
#
field :lndhub_api_url, type: :string,
default: ENV["LNDHUB_API_URL"].presence
field :lndhub_enabled, type: :boolean,
default: ENV["LNDHUB_API_URL"].present?
field :lndhub_admin_token, type: :string,
default: ENV["LNDHUB_ADMIN_TOKEN"].presence
field :lndhub_admin_enabled, type: :boolean,
default: ENV["LNDHUB_ADMIN_UI"] || false
field :lndhub_public_key, type: :string,
default: (ENV["LNDHUB_PUBLIC_KEY"] || "")
field :lndhub_keysend_enabled, type: :boolean,
default: -> { self.lndhub_public_key.present? }
#
# Mastodon
#
field :mastodon_public_url, type: :string,
default: ENV["MASTODON_PUBLIC_URL"].presence
field :mastodon_enabled, type: :boolean,
default: ENV["MASTODON_PUBLIC_URL"].present?
field :mastodon_address_domain, type: :string,
default: ENV["MASTODON_ADDRESS_DOMAIN"].presence || self.primary_domain
#
# MediaWiki
#
field :mediawiki_public_url, type: :string,
default: ENV["MEDIAWIKI_PUBLIC_URL"].presence
field :mediawiki_enabled, type: :boolean,
default: ENV["MEDIAWIKI_PUBLIC_URL"].present?
#
# Nostr
#
field :nostr_enabled, type: :boolean,
default: ENV["NOSTR_PRIVATE_KEY"].present?
field :nostr_private_key, type: :string,
default: ENV["NOSTR_PRIVATE_KEY"].presence
field :nostr_public_key, type: :string,
default: ENV["NOSTR_PUBLIC_KEY"].presence
field :nostr_relay_url, type: :string,
default: ENV["NOSTR_RELAY_URL"].presence
field :nostr_zaps_relay_limit, type: :integer,
default: 12
#
# OpenCollective
#
field :opencollective_enabled, type: :boolean, default: true
#
# RemoteStorage
#
field :remotestorage_enabled, type: :boolean,
default: ENV["RS_STORAGE_URL"].present?
field :rs_storage_url, type: :string,
default: ENV["RS_STORAGE_URL"].presence
field :rs_redis_url, type: :string,
default: ENV["RS_REDIS_URL"] || "redis://localhost:6379/1"
#
# E-Mail Service
#
field :email_enabled, type: :boolean,
default: ENV["EMAIL_SMTP_HOST"].present?
# field :email_smtp_host, type: :string,
# default: ENV["EMAIL_SMTP_HOST"].presence
#
# field :email_smtp_port, type: :string,
# default: ENV["EMAIL_SMTP_PORT"].presence || 587
#
# field :email_smtp_enable_starttls, type: :string,
# default: ENV["EMAIL_SMTP_PORT"].presence || true
#
# field :email_auth_method, type: :string,
# default: ENV["EMAIL_AUTH_METHOD"].presence || "plain"
#
# field :email_imap_host, type: :string,
# default: ENV["EMAIL_IMAP_HOST"].presence
#
# field :email_imap_port, type: :string,
# default: ENV["EMAIL_IMAP_PORT"].presence || 993
def self.default_services
# TODO Make configurable from respective service settings page
%w[ discourse gitea mastodon mediawiki remotestorage xmpp ]
Dir[Rails.root.join('app', 'models', 'concerns', 'settings', '*.rb')].each do |file|
require file
end
include Settings::GeneralSettings
include Settings::BtcpaySettings
include Settings::DiscourseSettings
include Settings::DroneCiSettings
include Settings::EjabberdSettings
include Settings::EmailSettings
include Settings::GiteaSettings
include Settings::LightningNetworkSettings
include Settings::MastodonSettings
include Settings::MediaWikiSettings
include Settings::NostrSettings
include Settings::OpenCollectiveSettings
include Settings::RemoteStorageSettings
include Settings::XmppSettings
def self.available_services
known_services = SERVICES[:external].keys
known_services.select {|s| Setting.send "#{s}_enabled?" }
end
field :default_services, type: :array,
default: self.available_services
end
+2 -2
View File
@@ -180,14 +180,14 @@ class User < ApplicationRecord
def enable_service(service)
current_services = services_enabled
new_services = Array(service).map(&:to_s)
services = (current_services + new_services).uniq
services = (current_services + new_services).uniq.sort
ldap.replace_attribute(dn, :serviceEnabled, services)
end
def disable_service(service)
current_services = services_enabled
disabled_services = Array(service).map(&:to_s)
services = (current_services - disabled_services).uniq
services = (current_services - disabled_services).uniq.sort
ldap.replace_attribute(dn, :serviceEnabled, services)
end
@@ -9,18 +9,36 @@
<%= render partial: "admin/settings/errors", locals: { errors: @errors } %>
<% end %>
<label class="block">
<p class="font-bold mb-1">Reserved usernames</p>
<p class="text-gray-500">
These usernames cannot be registered as accounts:
</p>
<ul role="list">
<%= render FormElements::FieldsetComponent.new(
title: "Reserved usernames",
description: "These usernames cannot be registered as accounts."
) do %>
<%= f.text_area :reserved_usernames,
value: Setting.reserved_usernames.join("\n"),
class: "h-44 mb-2" %>
class: "h-44 w-60" %>
<p class="text-sm text-gray-500">
One username per line
</p>
</label>
<% end %>
<li>
<p class="font-bold mb-1">Default services</p>
<p class="text-gray-500">
These services are enabled for new users by default after signup.
</p>
<div class="flex flex-wrap gap-x-6 gap-y-2">
<% Setting.available_services.each do |option| %>
<div class="md:inline-block">
<%= f.check_box :default_services,
{ multiple: true, checked: Setting.default_services.include?(option),
class: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-600 mr-0.5" },
option, nil %>
<%= f.label "default_services_#{option.parameterize}", service_human_name(option) %>
</div>
<% end %>
</div>
</li>
</ul>
</section>
<section>
@@ -19,6 +19,11 @@
title: "Public key",
description: "The corresponding public key of the accounts service"
) %>
<%= render FormElements::FieldsetResettableSettingComponent.new(
key: :nostr_public_key_primary_domain,
title: "Public key for primary domain (NIP-05)",
description: "(optional) A different pubkey to announce for the _@#{Setting.primary_domain} Nostr address"
) %>
<%= render FormElements::FieldsetResettableSettingComponent.new(
key: :nostr_relay_url,
title: "Relay URL",
@@ -1,5 +1,4 @@
<h3>RemoteStorage</h3>
<p class="text-red-600 mb-8">Feature currently in development.</p>
<ul role="list">
<%= render FormElements::FieldsetToggleComponent.new(
form: f,
+1 -1
View File
@@ -184,7 +184,7 @@
<td>XMPP (ejabberd)</td>
<td>
<%= render FormElements::ToggleComponent.new(
enabled: @services_enabled.include?("xmpp"),
enabled: @services_enabled.include?("ejabberd"),
input_enabled: false
) %>
</td>
+2
View File
@@ -0,0 +1,2 @@
config_path = Rails.root.join('config', 'services.yml')
SERVICES = YAML.load_file(config_path).deep_symbolize_keys.with_indifferent_access
+30
View File
@@ -0,0 +1,30 @@
internal:
btcpay:
name: BTCPay Server
postgres:
name: PostgreSQL
sentry:
name: Sentry
external:
discourse:
name: Discourse
droneci:
name: Drone CI
ejabberd:
display_name: Chat
email:
name: E-Mail
gitea:
name: Gitea
lndhub:
name: LNDHub
display_name: Lightning Network
mastodon:
name: Mastodon
mediawiki:
name: MediaWiki
nostr:
name: Nostr
remotestorage:
name: remoteStorage
display_name: Storage
Generated
+245
View File
@@ -0,0 +1,245 @@
{
"version": "3",
"packages": {
"specifiers": {
"jsr:@deno/cache-dir@0.8": "jsr:@deno/cache-dir@0.8.0",
"jsr:@deno/emit": "jsr:@deno/emit@0.45.0",
"jsr:@luca/esbuild-deno-loader@0.9": "jsr:@luca/esbuild-deno-loader@0.9.0",
"jsr:@std/assert@^0.213.1": "jsr:@std/assert@0.213.1",
"jsr:@std/assert@^0.218.2": "jsr:@std/assert@0.218.2",
"jsr:@std/assert@^0.223.0": "jsr:@std/assert@0.223.0",
"jsr:@std/bytes@^0.218.2": "jsr:@std/bytes@0.218.2",
"jsr:@std/encoding@0.213": "jsr:@std/encoding@0.213.1",
"jsr:@std/fmt@^0.218.2": "jsr:@std/fmt@0.218.2",
"jsr:@std/fs@^0.218.2": "jsr:@std/fs@0.218.2",
"jsr:@std/io@^0.218.2": "jsr:@std/io@0.218.2",
"jsr:@std/jsonc@0.213": "jsr:@std/jsonc@0.213.1",
"jsr:@std/path@0.213": "jsr:@std/path@0.213.1",
"jsr:@std/path@^0.218.2": "jsr:@std/path@0.218.2",
"jsr:@std/path@^0.223.0": "jsr:@std/path@0.223.0",
"npm:esbuild@0.20": "npm:esbuild@0.20.2"
},
"jsr": {
"@deno/cache-dir@0.8.0": {
"integrity": "e87e80a404958f6350d903e6238b72afb92468378b0b32111f7a1e4916ac7fe7",
"dependencies": [
"jsr:@std/fmt@^0.218.2",
"jsr:@std/fs@^0.218.2",
"jsr:@std/io@^0.218.2",
"jsr:@std/path@^0.218.2"
]
},
"@deno/emit@0.45.0": {
"integrity": "b59d632e61dbe4be7e9e61235f02ad08ff124c714c31deb080c4de778da1894d",
"dependencies": [
"jsr:@deno/cache-dir@0.8",
"jsr:@std/path@^0.223.0"
]
},
"@luca/esbuild-deno-loader@0.9.0": {
"integrity": "288bbcede5c8a6f97e635f8fa4df779b13440ee0c0506d9e478fb6537789dc93",
"dependencies": [
"jsr:@std/encoding@0.213",
"jsr:@std/jsonc@0.213",
"jsr:@std/path@0.213",
"npm:esbuild@0.20"
]
},
"@std/assert@0.213.1": {
"integrity": "24c28178b30c8e0782c18e8e94ea72b16282207569cdd10ffb9d1d26f2edebfe"
},
"@std/assert@0.218.2": {
"integrity": "7f0a5a1a8cf86607cd6c2c030584096e1ffad27fc9271429a8cb48cfbdee5eaf"
},
"@std/assert@0.223.0": {
"integrity": "eb8d6d879d76e1cc431205bd346ed4d88dc051c6366365b1af47034b0670be24"
},
"@std/bytes@0.218.2": {
"integrity": "91fe54b232dcca73856b79a817247f4a651dbb60d51baafafb6408c137241670"
},
"@std/encoding@0.213.1": {
"integrity": "fcbb6928713dde941a18ca5db88ca1544d0755ec8fb20fe61e2dc8144b390c62"
},
"@std/fmt@0.218.2": {
"integrity": "99526449d2505aa758b6cbef81e7dd471d8b28ec0dcb1491d122b284c548788a"
},
"@std/fs@0.218.2": {
"integrity": "dd9431453f7282e8c577cc22c9e6d036055a9a980b5549f887d6012969fabcca"
},
"@std/io@0.218.2": {
"integrity": "c64fbfa087b7c9d4d386c5672f291f607d88cb7d44fc299c20c713e345f2785f",
"dependencies": [
"jsr:@std/assert@^0.218.2",
"jsr:@std/bytes@^0.218.2"
]
},
"@std/jsonc@0.213.1": {
"integrity": "5578f21aa583b7eb7317eed077ffcde47b294f1056bdbb9aacec407758637bfe",
"dependencies": [
"jsr:@std/assert@^0.213.1"
]
},
"@std/path@0.213.1": {
"integrity": "f187bf278a172752e02fcbacf6bd78a335ed320d080a7ed3a5a59c3e88abc673",
"dependencies": [
"jsr:@std/assert@^0.213.1"
]
},
"@std/path@0.218.2": {
"integrity": "b568fd923d9e53ad76d17c513e7310bda8e755a3e825e6289a0ce536404e2662",
"dependencies": [
"jsr:@std/assert@^0.218.2"
]
},
"@std/path@0.223.0": {
"integrity": "593963402d7e6597f5a6e620931661053572c982fc014000459edc1f93cc3989",
"dependencies": [
"jsr:@std/assert@^0.223.0"
]
}
},
"npm": {
"@esbuild/aix-ppc64@0.20.2": {
"integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
"dependencies": {}
},
"@esbuild/android-arm64@0.20.2": {
"integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
"dependencies": {}
},
"@esbuild/android-arm@0.20.2": {
"integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
"dependencies": {}
},
"@esbuild/android-x64@0.20.2": {
"integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
"dependencies": {}
},
"@esbuild/darwin-arm64@0.20.2": {
"integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
"dependencies": {}
},
"@esbuild/darwin-x64@0.20.2": {
"integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
"dependencies": {}
},
"@esbuild/freebsd-arm64@0.20.2": {
"integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
"dependencies": {}
},
"@esbuild/freebsd-x64@0.20.2": {
"integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
"dependencies": {}
},
"@esbuild/linux-arm64@0.20.2": {
"integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
"dependencies": {}
},
"@esbuild/linux-arm@0.20.2": {
"integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
"dependencies": {}
},
"@esbuild/linux-ia32@0.20.2": {
"integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
"dependencies": {}
},
"@esbuild/linux-loong64@0.20.2": {
"integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
"dependencies": {}
},
"@esbuild/linux-mips64el@0.20.2": {
"integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
"dependencies": {}
},
"@esbuild/linux-ppc64@0.20.2": {
"integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
"dependencies": {}
},
"@esbuild/linux-riscv64@0.20.2": {
"integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
"dependencies": {}
},
"@esbuild/linux-s390x@0.20.2": {
"integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
"dependencies": {}
},
"@esbuild/linux-x64@0.20.2": {
"integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
"dependencies": {}
},
"@esbuild/netbsd-x64@0.20.2": {
"integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
"dependencies": {}
},
"@esbuild/openbsd-x64@0.20.2": {
"integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
"dependencies": {}
},
"@esbuild/sunos-x64@0.20.2": {
"integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
"dependencies": {}
},
"@esbuild/win32-arm64@0.20.2": {
"integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
"dependencies": {}
},
"@esbuild/win32-ia32@0.20.2": {
"integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
"dependencies": {}
},
"@esbuild/win32-x64@0.20.2": {
"integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
"dependencies": {}
},
"esbuild@0.20.2": {
"integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
"dependencies": {
"@esbuild/aix-ppc64": "@esbuild/aix-ppc64@0.20.2",
"@esbuild/android-arm": "@esbuild/android-arm@0.20.2",
"@esbuild/android-arm64": "@esbuild/android-arm64@0.20.2",
"@esbuild/android-x64": "@esbuild/android-x64@0.20.2",
"@esbuild/darwin-arm64": "@esbuild/darwin-arm64@0.20.2",
"@esbuild/darwin-x64": "@esbuild/darwin-x64@0.20.2",
"@esbuild/freebsd-arm64": "@esbuild/freebsd-arm64@0.20.2",
"@esbuild/freebsd-x64": "@esbuild/freebsd-x64@0.20.2",
"@esbuild/linux-arm": "@esbuild/linux-arm@0.20.2",
"@esbuild/linux-arm64": "@esbuild/linux-arm64@0.20.2",
"@esbuild/linux-ia32": "@esbuild/linux-ia32@0.20.2",
"@esbuild/linux-loong64": "@esbuild/linux-loong64@0.20.2",
"@esbuild/linux-mips64el": "@esbuild/linux-mips64el@0.20.2",
"@esbuild/linux-ppc64": "@esbuild/linux-ppc64@0.20.2",
"@esbuild/linux-riscv64": "@esbuild/linux-riscv64@0.20.2",
"@esbuild/linux-s390x": "@esbuild/linux-s390x@0.20.2",
"@esbuild/linux-x64": "@esbuild/linux-x64@0.20.2",
"@esbuild/netbsd-x64": "@esbuild/netbsd-x64@0.20.2",
"@esbuild/openbsd-x64": "@esbuild/openbsd-x64@0.20.2",
"@esbuild/sunos-x64": "@esbuild/sunos-x64@0.20.2",
"@esbuild/win32-arm64": "@esbuild/win32-arm64@0.20.2",
"@esbuild/win32-ia32": "@esbuild/win32-ia32@0.20.2",
"@esbuild/win32-x64": "@esbuild/win32-x64@0.20.2"
}
}
}
},
"remote": {
"https://deno.land/x/denoflate@1.2.1/mod.ts": "f5628e44b80b3d80ed525afa2ba0f12408e3849db817d47a883b801f9ce69dd6",
"https://deno.land/x/denoflate@1.2.1/pkg/denoflate.js": "b9f9ad9457d3f12f28b1fb35c555f57443427f74decb403113d67364e4f2caf4",
"https://deno.land/x/denoflate@1.2.1/pkg/denoflate_bg.wasm.js": "d581956245407a2115a3d7e8d85a9641c032940a8e810acbd59ca86afd34d44d",
"https://deno.land/x/esbuild@v0.20.1/mod.js": "d50e500b53ce67e31116beba3916b0f9275c0e1cc20bc5cadc0fc1b7a3b06fd9"
},
"workspace": {
"packageJson": {
"dependencies": [
"npm:@jsr/nostrify__nostrify",
"npm:@tailwindcss/forms@^0.5.3",
"npm:autoprefixer@^10.4.13",
"npm:postcss-flexbugs-fixes@^5.0.2",
"npm:postcss-import@^15.0.1",
"npm:postcss-nested@^6.0.0",
"npm:postcss-preset-env@^7.8.3",
"npm:postcss@^8.4.19",
"npm:tailwindcss@^3.2.4"
]
}
}
}
+14
View File
@@ -0,0 +1,14 @@
namespace :deno do
desc "Download and prepare a Deno package for importmap"
task :prepare, [:package, :version] => :environment do |t, args|
unless args[:package] && args[:version]
raise "Usage: rake deno:prepare[package-name,version]"
end
# Build the package
system "deno run -A scripts/build_deno_package.ts #{args[:package]} #{args[:version]}"
# Pin the package using importmap
# system "bin/importmap pin #{args[:package]} --to vendor/javascript/#{args[:package]}/build.js"
end
end
+2 -1
View File
@@ -2,6 +2,7 @@
"name": "akkounts",
"private": true,
"dependencies": {
"@nostrify/nostrify": "npm:@jsr/nostrify__nostrify",
"@tailwindcss/forms": "^0.5.3",
"autoprefixer": "^10.4.13",
"postcss": "^8.4.19",
@@ -11,7 +12,7 @@
"postcss-preset-env": "^7.8.3",
"tailwindcss": "^3.2.4"
},
"version": "0.9.0",
"version": "0.10.0",
"scripts": {
"build:css:tailwind": "tailwindcss --postcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css",
"build:css": "yarn run build:css:tailwind"
+18
View File
@@ -0,0 +1,18 @@
import { bundle } from "jsr:@deno/emit";
const [packageName, version] = Deno.args;
if (!packageName || !version) {
console.error('Usage: deno run -A build_deno_package.ts <package-name> <version>');
process.exit(1);
}
const result = await bundle(
new URL(`https://jsr.io/${packageName}/${version}/mod.ts`),
);
const { code } = result;
const buildFolder = `vendor/javascript/${packageName}`;
const buildFile = `${buildFolder}/build.js`
await Deno.mkdir(buildFolder, { recursive: true });
Deno.writeTextFileSync(buildFile, code);
+25
View File
@@ -0,0 +1,25 @@
require 'rails_helper'
describe ServicesHelper do
describe "#service_human_name" do
it "returns the human name when it's configured" do
expect(service_human_name("mastodon")).to eq("Mastodon")
end
it "returns the key when there is no human name" do
expect(service_human_name("ejabberd")).to eq("ejabberd")
end
end
describe "#service_display_name" do
it "returns the display name when it's configured" do
expect(service_display_name("lndhub")).to eq("Lightning Network")
end
it "returns the human name when there is no display name" do
expect(service_display_name("mastodon")).to eq("Mastodon")
end
end
end
+2 -2
View File
@@ -44,7 +44,7 @@ RSpec.describe CreateLdapUserJob, type: :job do
it "adds default services for pre-confirmed accounts" do
allow(ldap_client_mock).to receive(:add) # spy on mock
allow(Setting).to receive(:default_services).and_return(["xmpp", "discourse"])
Setting.default_services = ["ejabberd", "discourse"]
perform_enqueued_jobs { job_for_preconfirmed_account }
@@ -56,7 +56,7 @@ RSpec.describe CreateLdapUserJob, type: :job do
sn: "halfinney",
uid: "halfinney",
mail: "halfinney@example.com",
serviceEnabled: ["xmpp", "discourse"],
serviceEnabled: ["ejabberd", "discourse"],
userPassword: "remember-remember-the-5th-of-november"
}
)
+1 -1
View File
@@ -13,7 +13,7 @@ RSpec.describe XmppExchangeContactsJob, type: :job do
before do
stub_request(:post, "http://xmpp.example.com/api/add_rosteritem")
.to_return(status: 200, body: "", headers: {})
allow_any_instance_of(User).to receive(:services_enabled).and_return(["xmpp"])
allow_any_instance_of(User).to receive(:services_enabled).and_return(["ejabberd"])
end
it "posts add_rosteritem commands to the ejabberd API" do
+25
View File
@@ -0,0 +1,25 @@
require 'rails_helper'
RSpec.describe Setting, type: :model do
describe ".available_services" do
before do
Setting.discourse_enabled = true
Setting.ejabberd_enabled = true
Setting.email_enabled = false
Setting.gitea_enabled = false
Setting.lndhub_enabled = true
Setting.mastodon_enabled = true
Setting.mediawiki_enabled = false
Setting.nostr_enabled = false
Setting.remotestorage_enabled = true
end
it "contains all enabled services" do
expect(Setting.available_services).to eq(%w[
discourse ejabberd lndhub mastodon remotestorage
])
end
end
end
+9 -9
View File
@@ -78,9 +78,9 @@ RSpec.describe User, type: :model do
it "returns the entries from the LDAP service attribute" do
expect(user).to receive(:ldap_entry).and_return({
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
services_enabled: ["discourse", "email", "gitea", "wiki", "xmpp"]
services_enabled: ["discourse", "ejabberd", "email", "gitea", "wiki"]
})
expect(user.services_enabled).to eq(["discourse", "email", "gitea", "wiki", "xmpp"])
expect(user.services_enabled).to eq(["discourse", "ejabberd", "email", "gitea", "wiki"])
end
end
@@ -88,7 +88,7 @@ RSpec.describe User, type: :model do
before do
allow(user).to receive(:ldap_entry).and_return({
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
services_enabled: ["gitea", "xmpp"]
services_enabled: ["ejabberd", "gitea"]
})
end
@@ -121,9 +121,9 @@ RSpec.describe User, type: :model do
it "adds multiple service to the LDAP entry" do
expect_any_instance_of(LdapService).to receive(:replace_attribute)
.with(dn, :serviceEnabled, ["discourse", "gitea", "wiki", "xmpp"]).and_return(true)
.with(dn, :serviceEnabled, ["discourse", "ejabberd", "gitea", "wiki"]).and_return(true)
user.enable_service([:wiki, :xmpp])
user.enable_service([:ejabberd, :wiki])
end
end
@@ -131,7 +131,7 @@ RSpec.describe User, type: :model do
before do
allow(user).to receive(:ldap_entry).and_return({
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
services_enabled: ["discourse", "gitea", "xmpp"]
services_enabled: ["discourse", "ejabberd", "gitea"]
})
allow(user).to receive(:dn).and_return(dn)
end
@@ -140,14 +140,14 @@ RSpec.describe User, type: :model do
expect_any_instance_of(LdapService).to receive(:replace_attribute)
.with(dn, :serviceEnabled, ["discourse", "gitea"]).and_return(true)
user.disable_service(:xmpp)
user.disable_service(:ejabberd)
end
it "removes multiple services from the LDAP entry" do
expect_any_instance_of(LdapService).to receive(:replace_attribute)
.with(dn, :serviceEnabled, ["discourse"]).and_return(true)
user.disable_service([:xmpp, "gitea"])
user.disable_service([:ejabberd, "gitea"])
end
end
@@ -178,7 +178,7 @@ RSpec.describe User, type: :model do
after { clear_enqueued_jobs }
it "enables default services" do
expect(user).to receive(:enable_service).with(%w[ discourse gitea mastodon mediawiki xmpp ])
expect(user).to receive(:enable_service).with(Setting.default_services)
user.send :devise_after_confirmation
end
+9 -3
View File
@@ -44,7 +44,7 @@ RSpec.describe "WebFinger", type: :request do
before do
allow_any_instance_of(User).to receive(:ldap_entry).and_return({
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
services_enabled: ["xmpp"]
services_enabled: ["ejabberd"]
})
end
@@ -92,7 +92,13 @@ RSpec.describe "WebFinger", type: :request do
expect(rs_link["href"]).to eql("#{Setting.rs_storage_url}/tony")
oauth_url = rs_link["properties"]["http://tools.ietf.org/html/rfc6749#section-4.2"]
expect(oauth_url).to eql("http://www.example.com/rs/oauth/tony")
expect(oauth_url).to eql("http://accounts.kosmos.org/rs/oauth/tony")
end
it "returns CORS headers" do
get "/.well-known/nostr.json?name=bobdylan"
expect(response.headers['Access-Control-Allow-Origin']).to eq("*")
expect(response.headers['Access-Control-Allow-Methods']).to eq('GET')
end
end
@@ -100,7 +106,7 @@ RSpec.describe "WebFinger", type: :request do
before do
allow_any_instance_of(User).to receive(:ldap_entry).and_return({
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
services_enabled: ["xmpp"]
services_enabled: ["ejabberd"]
})
end
+34 -2
View File
@@ -46,6 +46,12 @@ RSpec.describe "Well-known URLs", type: :request do
expect(res["names"]["bobdylan"]).to eq(user.nostr_pubkey)
end
it "returns CORS headers" do
get "/.well-known/nostr.json?name=bobdylan"
expect(response.headers['Access-Control-Allow-Origin']).to eq("*")
expect(response.headers['Access-Control-Allow-Methods']).to eq('GET')
end
context "without relay configured" do
before do
Setting.nostr_relay_url = ""
@@ -73,10 +79,36 @@ RSpec.describe "Well-known URLs", type: :request do
end
describe "placeholder username for domain's own pubkey" do
it "returns the configured nostr pubkey" do
describe "for primary domain" do
context "no different pubkey configured for primary domain" do
it "returns the akkounts nostr pubkey" do
get "/.well-known/nostr.json?name=_"
res = JSON.parse(response.body)
expect(res["names"]["_"]).to eq(Setting.nostr_public_key)
expect(res["names"]["_"]).to eq("bdd76ce2934b2f591f9fad2ebe9da18f20d2921de527494ba00eeaa0a0efadcf")
end
end
context "different pubkey configured for primary domain" do
before do
Setting.nostr_public_key_primary_domain = "b3e8f62fbe41217ffc0aa1e178d297339932d8ba4f46d9c7df3b61575e78fecc"
end
it "returns the primary domain's nostr pubkey" do
get "/.well-known/nostr.json?name=_"
res = JSON.parse(response.body)
expect(res["names"]["_"]).to eq("b3e8f62fbe41217ffc0aa1e178d297339932d8ba4f46d9c7df3b61575e78fecc")
end
end
end
describe "for akkounts domain" do
it "returns the configured nostr pubkey" do
headers = { "X-Forwarded-Host" => "accounts.kosmos.org" }
get "/.well-known/nostr.json?name=_"
res = JSON.parse(response.body)
expect(res["names"]["_"]).to eq("bdd76ce2934b2f591f9fad2ebe9da18f20d2921de527494ba00eeaa0a0efadcf")
end
end
context "with relay configured" do
+178
View File
@@ -108,6 +108,90 @@
resolved "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz"
integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==
"@jsr/nostrify__types@^0.35.0":
version "0.35.0"
resolved "https://npm.jsr.io/~/11/@jsr/nostrify__types/0.35.0.tgz#449D2F6DAE75E5FF660595CF3C45437D14409AF4"
integrity sha512-dukOLFxyF7JwDvORLvb3PwMFs1HOBIkTyiewkujiGPaQ7FjvvGMiqY/QxbG0qZX5AmTtS65c/lLlg/ni1flrGQ==
"@jsr/std__assert@^0.224.0":
version "0.224.0"
resolved "https://npm.jsr.io/~/11/@jsr/std__assert/0.224.0.tgz#B6D7D05F367C7991EC67B19758EDB5BD0D86B385"
integrity sha512-RB0p0ydybgKSfTba6kHWytfpEJ0CBPi+byxZikLYa51L9uLINW52/j6n4KuiLFoh2cdFfpNZSNMY/dzQPW90DQ==
dependencies:
"@jsr/std__fmt" "^0.224.0"
"@jsr/std__internal" "^0.224.0"
"@jsr/std__crypto@^0.224.0":
version "0.224.0"
resolved "https://npm.jsr.io/~/11/@jsr/std__crypto/0.224.0.tgz#FA994A4B99E2D48B983E40B25D65A57BB405A04B"
integrity sha512-qzZWI8VnH215FS7hmQsAeNafjLMkmSl1OOvexorVUEf1Zl9omHSN87MwIjtmyVXGLtpGRLzIhKXbeup1xO69Zw==
dependencies:
"@jsr/std__assert" "^0.224.0"
"@jsr/std__encoding" "^0.224.0"
"@jsr/std__encoding@^0.224.0", "@jsr/std__encoding@^0.224.1":
version "0.224.3"
resolved "https://npm.jsr.io/~/11/@jsr/std__encoding/0.224.3.tgz#ADBBF3F2EFA8C4F7A9063CFEF679AFF46B984FF0"
integrity sha512-zAuX2QV1zwJ5RSmrnDGVerAtN3pBXpYYNlGzhERW9AiQ1UJd2/xruyB3i5NdTWy2OK2pjETswOj+0+prYTPlxQ==
"@jsr/std__fmt@^0.224.0":
version "0.224.0"
resolved "https://npm.jsr.io/~/11/@jsr/std__fmt/0.224.0.tgz#8079EB480C2BE2414430ECCF98F24C1C325B1277"
integrity sha512-lyrH5LesMB897QW0NIbZlGp72Ucopj2hMZW2wqB0NyZhuXfLH2sPBIUpCSf87kRKTGnx90JV905w4iTp0TD+Sg==
"@jsr/std__internal@^0.224.0":
version "0.224.0"
resolved "https://npm.jsr.io/~/11/@jsr/std__internal/0.224.0.tgz#939D6DE44B7340EB097C464AFD7E7476E814B6BE"
integrity sha512-inYzKOGAFK2tyy1D4NfwlbPiqEcSaXfOms3Tm4Y+1LmKSYOeB9wjqWHF4y/BJuYj8XUv61F7eaHaIw6NIlhBWg==
dependencies:
"@jsr/std__fmt" "^0.224.0"
"@noble/ciphers@^0.5.1":
version "0.5.3"
resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.5.3.tgz#48b536311587125e0d0c1535f73ec8375cd76b23"
integrity sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==
"@noble/curves@1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35"
integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==
dependencies:
"@noble/hashes" "1.3.2"
"@noble/curves@~1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d"
integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==
dependencies:
"@noble/hashes" "1.3.1"
"@noble/curves@~1.6.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.6.0.tgz#be5296ebcd5a1730fccea4786d420f87abfeb40b"
integrity sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==
dependencies:
"@noble/hashes" "1.5.0"
"@noble/hashes@1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9"
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==
"@noble/hashes@1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39"
integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==
"@noble/hashes@1.5.0", "@noble/hashes@~1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.5.0.tgz#abadc5ca20332db2b1b2aa3e496e9af1213570b0"
integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==
"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1":
version "1.3.3"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699"
integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
@@ -129,6 +213,66 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@nostrify/nostrify@npm:@jsr/nostrify__nostrify":
version "0.36.0"
resolved "https://npm.jsr.io/~/11/@jsr/nostrify__nostrify/0.36.0.tgz#9A94131A51DCAA501C2AA69878DEE453E5796653"
integrity sha512-8M/VHxP0qS1+nrt+GiDRBu3AtDaZhlOuPMH/BkqPtIyp1tAqBXAb6yCrAhxw/iORGUUronJpet1U8bEQz9K0xg==
dependencies:
"@jsr/nostrify__types" "^0.35.0"
"@jsr/std__crypto" "^0.224.0"
"@jsr/std__encoding" "^0.224.1"
"@scure/base" "^1.1.6"
"@scure/bip32" "^1.4.0"
"@scure/bip39" "^1.3.0"
lru-cache "^10.2.0"
nostr-tools "^2.7.0"
websocket-ts "^2.1.5"
zod "^3.23.8"
"@scure/base@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==
"@scure/base@^1.1.6", "@scure/base@~1.1.0", "@scure/base@~1.1.7", "@scure/base@~1.1.8":
version "1.1.9"
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1"
integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==
"@scure/bip32@1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.1.tgz#7248aea723667f98160f593d621c47e208ccbb10"
integrity sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==
dependencies:
"@noble/curves" "~1.1.0"
"@noble/hashes" "~1.3.1"
"@scure/base" "~1.1.0"
"@scure/bip32@^1.4.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.5.0.tgz#dd4a2e1b8a9da60e012e776d954c4186db6328e6"
integrity sha512-8EnFYkqEQdnkuGBVpCzKxyIwDCBLDVj3oiX0EKUFre/tOjL/Hqba1D6n/8RcmaQy4f95qQFrO2A8Sr6ybh4NRw==
dependencies:
"@noble/curves" "~1.6.0"
"@noble/hashes" "~1.5.0"
"@scure/base" "~1.1.7"
"@scure/bip39@1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.1.tgz#5cee8978656b272a917b7871c981e0541ad6ac2a"
integrity sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==
dependencies:
"@noble/hashes" "~1.3.0"
"@scure/base" "~1.1.0"
"@scure/bip39@^1.3.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.4.0.tgz#664d4f851564e2e1d4bffa0339f9546ea55960a6"
integrity sha512-BEEm6p8IueV/ZTfQLp/0vhw4NPnT9oWf5+28nvmeUICjP99f4vr2d+qc7AVGDDtwRep6ifR43Yed9ERVmiITzw==
dependencies:
"@noble/hashes" "~1.5.0"
"@scure/base" "~1.1.8"
"@tailwindcss/forms@^0.5.3":
version "0.5.3"
resolved "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz"
@@ -399,6 +543,11 @@ lilconfig@^2.0.5, lilconfig@^2.0.6:
resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz"
integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==
lru-cache@^10.2.0:
version "10.4.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119"
integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
merge2@^1.3.0:
version "1.4.1"
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
@@ -450,6 +599,25 @@ normalize-range@^0.1.2:
resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz"
integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=
nostr-tools@^2.7.0:
version "2.7.2"
resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-2.7.2.tgz#74a6ff543a81da1dcce9563b9317faa17221acce"
integrity sha512-Bq3Ug0SZFtgtL1+0wCnAe8AJtI7yx/00/a2nUug9SkhfOwlKS92Tef12iCK9FdwXw+oFZWMtRnSwcLayQso+xA==
dependencies:
"@noble/ciphers" "^0.5.1"
"@noble/curves" "1.2.0"
"@noble/hashes" "1.3.1"
"@scure/base" "1.1.1"
"@scure/bip32" "1.3.1"
"@scure/bip39" "1.2.1"
optionalDependencies:
nostr-wasm v0.1.0
nostr-wasm@v0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/nostr-wasm/-/nostr-wasm-0.1.0.tgz#17af486745feb2b7dd29503fdd81613a24058d94"
integrity sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==
object-hash@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz"
@@ -901,6 +1069,11 @@ util-deprecate@^1.0.2:
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
websocket-ts@^2.1.5:
version "2.1.5"
resolved "https://registry.yarnpkg.com/websocket-ts/-/websocket-ts-2.1.5.tgz#b6b51f0afca89d6bc7ff71c9e74540f19ae0262c"
integrity sha512-rCNl9w6Hsir1azFm/pbjBEFzLD/gi7Th5ZgOxMifB6STUfTSovYAzryWw0TRvSZ1+Qu1Z5Plw4z42UfTNA9idA==
xtend@^4.0.2:
version "4.0.2"
resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz"
@@ -910,3 +1083,8 @@ yaml@^1.10.2:
version "1.10.2"
resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
zod@^3.23.8:
version "3.23.8"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d"
integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==