Compare commits
1 Commits
feature/no
...
docs/integ
| Author | SHA1 | Date | |
|---|---|---|---|
|
14c5dd22d6
|
13
Dockerfile
13
Dockerfile
@@ -1,11 +1,18 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
FROM ruby:3.3.4
|
FROM debian:bullseye-slim as base
|
||||||
|
|
||||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||||
|
|
||||||
RUN apt-get update -qq && apt-get install -y --no-install-recommends curl \
|
# TODO Remove when upstream Ruby works properly on Apple silicon
|
||||||
ldap-utils tini libvips
|
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 install -y --no-install-recommends curl ldap-utils tini libvips
|
||||||
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
|
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
|
||||||
RUN apt-get update && apt-get install -y nodejs
|
RUN apt-get update && apt-get install -y nodejs
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
<div class="w-[72vw] md:w-[500px]">
|
|
||||||
<header class="absolute z-10 h-36 sm:h-44 inset-x-1 top-1 rounded-t
|
|
||||||
bg-cover bg-center bg-gray-50"
|
|
||||||
style="background-image: url('<%= @profile["banner"]%>');">
|
|
||||||
<div class="inline-block z-20 size-28 sm:size-32 ml-4 mt-16 sm:mt-20">
|
|
||||||
<% if @profile["picture"].present? %>
|
|
||||||
<img src="<%= @profile["picture"] %>"
|
|
||||||
class="inline-block size:28 sm:size-32 rounded-full border-2 border-white" />
|
|
||||||
<% else %>
|
|
||||||
<span class="inline-block size:28 sm:size-32 overflow-hidden rounded-full border-2 border-white bg-gray-100">
|
|
||||||
<svg class="size-full text-gray-300" fill="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path d="M24 20.993V24H0v-2.996A14.977 14.977 0 0112.004 15c4.904 0 9.26 2.354 11.996 5.993zM16.002 8.999a4 4 0 11-8 0 4 4 0 018 0z" />
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<main class="mt-44 sm:mt-52">
|
|
||||||
<%= form_for(@user, url: setting_path(:nostr), html: { :method => :put }) do |f| %>
|
|
||||||
<%= render FormElements::FieldsetComponent.new(tag: "div", title: "Display name") do %>
|
|
||||||
<%= f.text_field :display_name, value: @display_name, class: "w-full sm:w-3/5" %>
|
|
||||||
<% if @validation_errors.present? && @validation_errors[:display_name].present? %>
|
|
||||||
<p class="error-msg mt-2"><%= @validation_errors[:display_name].first %></p>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
<%= render FormElements::FieldsetComponent.new(tag: "div", title: "Nostr address (NIP-05)") do %>
|
|
||||||
<%= f.text_field :nip05_address, value: @profile["nip05"], class: "w-full sm:w-3/5" %>
|
|
||||||
<% if @validation_errors.present? && @validation_errors[:nip05_address].present? %>
|
|
||||||
<p class="error-msg mt-2"><%= @validation_errors[:nip05_address].first %></p>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
<%= render FormElements::FieldsetComponent.new(tag: "div", title: "Ligtning address for Zaps") do %>
|
|
||||||
<%= f.text_field :lud16_address, value: @profile["lud16"], class: "w-full sm:w-3/5" %>
|
|
||||||
<% if @validation_errors.present? && @validation_errors[:lud16_address].present? %>
|
|
||||||
<p class="error-msg mt-2"><%= @validation_errors[:lud16_address].first %></p>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
</main>
|
|
||||||
<footer>
|
|
||||||
<%# <%= @profile.inspect %>
|
|
||||||
<%# <%= @profile_event.inspect %>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Settings
|
|
||||||
class NostrEditProfileComponent < ViewComponent::Base
|
|
||||||
def initialize(user:, profile_event:)
|
|
||||||
if profile_event.present?
|
|
||||||
@user = user
|
|
||||||
@profile_event = profile_event
|
|
||||||
@profile = JSON.parse(profile_event["content"])
|
|
||||||
@display_name = @profile["display_name"] || @profile["displayName"]
|
|
||||||
|
|
||||||
if @profile["nip05"].present? && @profile["nip05"] == @user.address
|
|
||||||
# "Your profile's Nostr address is set to <strong>#{ user_address }</strong>"
|
|
||||||
else
|
|
||||||
# "Your profile's Nostr address is not set to <strong>#{ user_address }</strong> yet"
|
|
||||||
end
|
|
||||||
|
|
||||||
if @profile["lud16"].present? && @profile["lud16"] == @user.address
|
|
||||||
# "Your profile's Lightning address is set to <strong>#{ user_address }</strong>"
|
|
||||||
else
|
|
||||||
# "Your profile's Lightning address is not set to <strong>#{ user_address }</strong> yet"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
# "We could not find a profile for your public key"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<% @statuses.each do |status| %>
|
|
||||||
<%= render StatusTextComponent.new(
|
|
||||||
text: status[:text],
|
|
||||||
icon_name: status[:icon_name],
|
|
||||||
icon_color: status[:icon_color]
|
|
||||||
) %>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% if @status == 1 %>
|
|
||||||
<p class="mt-8">
|
|
||||||
<button class="btn-md btn-blue">
|
|
||||||
Edit my profile
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
<% elsif @status == 2 %>
|
|
||||||
<p class="mt-8">
|
|
||||||
<button class="btn-md btn-blue">
|
|
||||||
Create my profile
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
<% end %>
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Settings
|
|
||||||
class NostrProfileStatusComponent < ViewComponent::Base
|
|
||||||
def initialize(profile_event:, user_address:)
|
|
||||||
@statuses = []
|
|
||||||
|
|
||||||
if profile_event.present?
|
|
||||||
profile = JSON.parse(profile_event["content"])
|
|
||||||
|
|
||||||
@statuses.push({
|
|
||||||
text: "You have a public Nostr profile",
|
|
||||||
icon_name: "check-circle",
|
|
||||||
icon_color: "emerald-500"
|
|
||||||
})
|
|
||||||
|
|
||||||
if profile["nip05"].present? && profile["nip05"] == user_address
|
|
||||||
@statuses.push({
|
|
||||||
text: "Your profile's Nostr address is set to <strong>#{ user_address }</strong>",
|
|
||||||
icon_name: "check-circle",
|
|
||||||
icon_color: "emerald-500"
|
|
||||||
})
|
|
||||||
else
|
|
||||||
@statuses.push({
|
|
||||||
text: "Your profile's Nostr address is not set to <strong>#{ user_address }</strong> yet",
|
|
||||||
icon_name: "alert-octagon",
|
|
||||||
icon_color: "amber-500"
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
if profile["lud16"].present? && profile["lud16"] == user_address
|
|
||||||
@statuses.push({
|
|
||||||
text: "Your profile's Lightning address is set to <strong>#{ user_address }</strong>",
|
|
||||||
icon_name: "check-circle",
|
|
||||||
icon_color: "emerald-500"
|
|
||||||
})
|
|
||||||
else
|
|
||||||
@statuses.push({
|
|
||||||
text: "Your profile's Lightning address is not set to <strong>#{ user_address }</strong> yet",
|
|
||||||
icon_name: "alert-octagon",
|
|
||||||
icon_color: "amber-500"
|
|
||||||
})
|
|
||||||
end
|
|
||||||
else
|
|
||||||
@statuses.push({
|
|
||||||
text: "We could not find a profile for your public key",
|
|
||||||
icon_name: "alert-octagon",
|
|
||||||
icon_color: "amber-500"
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<%= render StatusTextComponent.new(
|
|
||||||
text: @text,
|
|
||||||
icon_name: @icon_name,
|
|
||||||
icon_color: @icon_color) %>
|
|
||||||
|
|
||||||
<% if @status == 1 %>
|
|
||||||
<p class="mt-8">
|
|
||||||
<button class="btn-md btn-blue">
|
|
||||||
Add the relay to my list
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
<% elsif @status == 2 %>
|
|
||||||
<p class="mt-8">
|
|
||||||
<button class="btn-md btn-blue">
|
|
||||||
Set up default relays
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
<% end %>
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Settings
|
|
||||||
class NostrRelayStatusComponent < ViewComponent::Base
|
|
||||||
def initialize(nip65_event:)
|
|
||||||
if nip65_event.present?
|
|
||||||
if relay_urls(nip65_event).any? { |r| r.include?("wss://nostr.kosmos.org") }
|
|
||||||
@text = "You have a relay list, and the Kosmos relay is part of it"
|
|
||||||
@icon_name = "check-circle"
|
|
||||||
@icon_color = "emerald-500"
|
|
||||||
@status = 0
|
|
||||||
else
|
|
||||||
@text = "The Kosmos relay is missing from your relay list"
|
|
||||||
@icon_name = "alert-octagon"
|
|
||||||
@icon_color = "amber-500"
|
|
||||||
@status = 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
@text = "We could not find a relay list for your public key"
|
|
||||||
@icon_name = "alert-octagon"
|
|
||||||
@icon_color = "amber-500"
|
|
||||||
@status = 2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def relay_urls(nip65_event)
|
|
||||||
nip65_event["tags"].select{ |t| t[0] == "r" }.map{ |t| t[1] }
|
|
||||||
# @inbox_relay_urls = relay_tags&.select{ |t| t[2] == "read" }&.map{ |t| t[1] }
|
|
||||||
# @outbox_relay_urls = relay_tags&.select{ |t| t[2] != "read" }&.map{ |t| t[1] }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<p class="flex gap-x-4 items-center">
|
|
||||||
<span class="inline-block h-6 w-6 grow-0 text-<%= @icon_color %>">
|
|
||||||
<%= render "icons/#{@icon_name}" %>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<%= raw @text %>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
class StatusTextComponent < ViewComponent::Base
|
|
||||||
def initialize(text:, icon_name:, icon_color:)
|
|
||||||
@text = text
|
|
||||||
@icon_name = icon_name
|
|
||||||
@icon_color = icon_color
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -9,12 +9,4 @@ class Admin::Settings::RegistrationsController < Admin::SettingsController
|
|||||||
success: "Settings saved"
|
success: "Settings saved"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def setting_params
|
|
||||||
params.require(:setting).permit([
|
|
||||||
:reserved_usernames, default_services: []
|
|
||||||
])
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,12 +9,11 @@ class Admin::SettingsController < Admin::BaseController
|
|||||||
changed_keys = []
|
changed_keys = []
|
||||||
|
|
||||||
setting_params.keys.each do |key|
|
setting_params.keys.each do |key|
|
||||||
next if clean_param(key).nil? ||
|
next if setting_params[key].nil? ||
|
||||||
(Setting.send(key).to_s == clean_param(key))
|
(Setting.send(key).to_s == setting_params[key].strip)
|
||||||
|
|
||||||
changed_keys.push(key)
|
changed_keys.push(key)
|
||||||
setting = Setting.new(var: key)
|
setting = Setting.new(var: key)
|
||||||
setting.value = clean_param(key)
|
setting.value = setting_params[key].strip
|
||||||
unless setting.valid?
|
unless setting.valid?
|
||||||
@errors.merge!(setting.errors)
|
@errors.merge!(setting.errors)
|
||||||
end
|
end
|
||||||
@@ -25,7 +24,7 @@ class Admin::SettingsController < Admin::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
changed_keys.each do |key|
|
changed_keys.each do |key|
|
||||||
Setting.send("#{key}=", clean_param(key))
|
Setting.send("#{key}=", setting_params[key].strip)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -38,12 +37,4 @@ class Admin::SettingsController < Admin::BaseController
|
|||||||
def setting_params
|
def setting_params
|
||||||
params.require(:setting).permit(Setting.editable_keys.map(&:to_sym))
|
params.require(:setting).permit(Setting.editable_keys.map(&:to_sym))
|
||||||
end
|
end
|
||||||
|
|
||||||
def clean_param(key)
|
|
||||||
if Setting.get_field(key)[:type] == :string
|
|
||||||
setting_params[key].strip
|
|
||||||
else
|
|
||||||
setting_params[key]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
class LnurlpayController < ApplicationController
|
class LnurlpayController < ApplicationController
|
||||||
before_action :check_service_available
|
before_action :check_service_available
|
||||||
before_action :find_user
|
before_action :find_user
|
||||||
before_action :set_cors_access_control_headers
|
before_action :set_cors_access_control_headers, only: [:invoice]
|
||||||
|
|
||||||
MIN_SATS = 10
|
MIN_SATS = 10
|
||||||
MAX_SATS = 1_000_000
|
MAX_SATS = 1_000_000
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ class Services::ChatController < Services::BaseController
|
|||||||
before_action :require_service_available
|
before_action :require_service_available
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@service_enabled = current_user.service_enabled?(:ejabberd)
|
@service_enabled = current_user.service_enabled?(:xmpp)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -4,13 +4,8 @@ require "bcrypt"
|
|||||||
class SettingsController < ApplicationController
|
class SettingsController < ApplicationController
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
before_action :set_main_nav_section
|
before_action :set_main_nav_section
|
||||||
before_action :set_settings_section, only: [
|
before_action :set_settings_section, only: [:show, :update, :update_email, :reset_email_password]
|
||||||
:show, :update, :update_email, :reset_email_password
|
before_action :set_user, only: [:show, :update, :update_email, :reset_email_password]
|
||||||
]
|
|
||||||
before_action :set_user, only: [
|
|
||||||
:show, :update, :update_email, :reset_email_password,
|
|
||||||
:fetch_nostr_user_metadata
|
|
||||||
]
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
redirect_to setting_path(:profile)
|
redirect_to setting_path(:profile)
|
||||||
@@ -133,28 +128,6 @@ class SettingsController < ApplicationController
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_nostr_user_metadata
|
|
||||||
if @user.nostr_pubkey.present?
|
|
||||||
outbox_relay_urls = nil
|
|
||||||
|
|
||||||
# if @nip65_event = NostrManager::DiscoverUserRelays.call(pubkey: @user.nostr_pubkey)
|
|
||||||
# relay_tags = @nip65_event["tags"].select{ |t| t[0] == "r" }
|
|
||||||
# outbox_relay_urls = relay_tags&.select{ |t| t[2] != "read" }&.map{ |t| t[1] }
|
|
||||||
# end
|
|
||||||
|
|
||||||
# @profile = NostrManager::DiscoverUserProfile.call(
|
|
||||||
# pubkey: @user.nostr_pubkey,
|
|
||||||
# relays: outbox_relay_urls
|
|
||||||
# )
|
|
||||||
@profile = {"content"=>"{\"name\":\"jimmy\",\"picture\":\"https://storage.kosmos.org/jimmy/public/shares/241028-1117-tony.jpg\",\"banner\":\"https://storage.kosmos.org/raucao/public/shares/240604-1517-1500x500.jpg\",\"nip05\":\"jimmy@kosmos.org\",\"lud16\":\"jimmy@kosmos.org\",\"pubkey\":\"07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3\",\"display_name\":\"Jimmy\",\"displayName\":\"Jimmy\",\"about\":\"I don't exist. Follow at your own peril.\"}", "created_at"=>1730114246, "id"=>"6b15b1308a61ee837bd3b50319978314650e435891c259f4ea499f819f35a4f6", "kind"=>0, "pubkey"=>"07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3", "sig"=>"4f681f4b95646bbf88a6eae9ca92c0f2ce5effecfa017556a23490f91a99243aedf81d956ee2466ed64fecb9a03b6b89cd80ff116df0178830977e203867d7ae", "tags"=>[]}
|
|
||||||
# @profile = {"content"=>"{\"name\":\"jimmy\",\"nip05\":\"jimmy@kosmos.org\",\"lud16\":\"jimmy@kosmos.org\",\"pubkey\":\"07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3\",\"display_name\":\"Jimmy\",\"displayName\":\"Jimmy\",\"about\":\"I don't exist. Follow at your own peril.\"}", "created_at"=>1730114246, "id"=>"6b15b1308a61ee837bd3b50319978314650e435891c259f4ea499f819f35a4f6", "kind"=>0, "pubkey"=>"07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3", "sig"=>"4f681f4b95646bbf88a6eae9ca92c0f2ce5effecfa017556a23490f91a99243aedf81d956ee2466ed64fecb9a03b6b89cd80ff116df0178830977e203867d7ae", "tags"=>[]}
|
|
||||||
else
|
|
||||||
@relays, @profile = [nil, nil]
|
|
||||||
end
|
|
||||||
|
|
||||||
render partial: 'nostr_user_metadata'
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_main_nav_section
|
def set_main_nav_section
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
class WebfingerController < WellKnownController
|
class WebfingerController < ApplicationController
|
||||||
before_action :allow_cross_origin_requests, only: [:show]
|
before_action :allow_cross_origin_requests, only: [:show]
|
||||||
|
|
||||||
|
layout false
|
||||||
|
|
||||||
def show
|
def show
|
||||||
resource = params[:resource]
|
resource = params[:resource]
|
||||||
|
|
||||||
@@ -74,7 +76,7 @@ class WebfingerController < WellKnownController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def remotestorage_link
|
def remotestorage_link
|
||||||
auth_url = new_rs_oauth_url(@username, host: Setting.accounts_domain)
|
auth_url = new_rs_oauth_url(@username)
|
||||||
storage_url = "#{Setting.rs_storage_url}/#{@username}"
|
storage_url = "#{Setting.rs_storage_url}/#{@username}"
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -89,4 +91,10 @@ class WebfingerController < WellKnownController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def allow_cross_origin_requests
|
||||||
|
return unless Rails.env.development?
|
||||||
|
headers['Access-Control-Allow-Origin'] = "*"
|
||||||
|
headers['Access-Control-Allow-Methods'] = "GET"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
class WellKnownController < ApplicationController
|
class WellKnownController < ApplicationController
|
||||||
before_action :require_nostr_enabled, only: [ :nostr ]
|
before_action :require_nostr_enabled, only: [ :nostr ]
|
||||||
before_action :allow_cross_origin_requests, only: [ :nostr ]
|
|
||||||
|
|
||||||
layout false
|
|
||||||
|
|
||||||
def nostr
|
def nostr
|
||||||
http_status :unprocessable_entity and return if params[:name].blank?
|
http_status :unprocessable_entity and return if params[:name].blank?
|
||||||
@@ -10,14 +7,8 @@ class WellKnownController < ApplicationController
|
|||||||
relay_url = Setting.nostr_relay_url.presence
|
relay_url = Setting.nostr_relay_url.presence
|
||||||
|
|
||||||
if params[:name] == "_"
|
if params[:name] == "_"
|
||||||
if domain == Setting.primary_domain
|
|
||||||
# pubkey for the primary domain without a username (e.g. kosmos.org)
|
# 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 } }
|
res = { names: { "_": Setting.nostr_public_key } }
|
||||||
end
|
|
||||||
|
|
||||||
res[:relays] = { "_" => [ relay_url ] } if relay_url
|
res[:relays] = { "_" => [ relay_url ] } if relay_url
|
||||||
else
|
else
|
||||||
@user = User.where(cn: params[:name], ou: domain).first
|
@user = User.where(cn: params[:name], ou: domain).first
|
||||||
@@ -39,9 +30,4 @@ class WellKnownController < ApplicationController
|
|||||||
def require_nostr_enabled
|
def require_nostr_enabled
|
||||||
http_status :not_found unless Setting.nostr_enabled?
|
http_status :not_found unless Setting.nostr_enabled?
|
||||||
end
|
end
|
||||||
|
|
||||||
def allow_cross_origin_requests
|
|
||||||
headers['Access-Control-Allow-Origin'] = "*"
|
|
||||||
headers['Access-Control-Allow-Methods'] = "GET"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
2
app/helpers/dashboard_helper.rb
Normal file
2
app/helpers/dashboard_helper.rb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module DashboardHelper
|
||||||
|
end
|
||||||
2
app/helpers/donations_helper.rb
Normal file
2
app/helpers/donations_helper.rb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module DonationsHelper
|
||||||
|
end
|
||||||
2
app/helpers/invitations_helper.rb
Normal file
2
app/helpers/invitations_helper.rb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module InvitationsHelper
|
||||||
|
end
|
||||||
2
app/helpers/lnurlpay_helper.rb
Normal file
2
app/helpers/lnurlpay_helper.rb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module LnurlpayHelper
|
||||||
|
end
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
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
app/helpers/settings_helper.rb
Normal file
2
app/helpers/settings_helper.rb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module SettingsHelper
|
||||||
|
end
|
||||||
2
app/helpers/signup_helper.rb
Normal file
2
app/helpers/signup_helper.rb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module SignupHelper
|
||||||
|
end
|
||||||
2
app/helpers/users_helper.rb
Normal file
2
app/helpers/users_helper.rb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module UsersHelper
|
||||||
|
end
|
||||||
2
app/helpers/wallet_helper.rb
Normal file
2
app/helpers/wallet_helper.rb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module WalletHelper
|
||||||
|
end
|
||||||
2
app/helpers/welcome_helper.rb
Normal file
2
app/helpers/welcome_helper.rb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module WelcomeHelper
|
||||||
|
end
|
||||||
@@ -2,8 +2,8 @@ class XmppExchangeContactsJob < ApplicationJob
|
|||||||
queue_as :default
|
queue_as :default
|
||||||
|
|
||||||
def perform(inviter, invitee)
|
def perform(inviter, invitee)
|
||||||
return unless inviter.service_enabled?(:ejabberd) &&
|
return unless inviter.service_enabled?(:xmpp) &&
|
||||||
invitee.service_enabled?(:ejabberd) &&
|
invitee.service_enabled?(:xmpp) &&
|
||||||
inviter.preferences[:xmpp_exchange_contacts_with_invitees]
|
inviter.preferences[:xmpp_exchange_contacts_with_invitees]
|
||||||
|
|
||||||
ejabberd = EjabberdApiClient.new
|
ejabberd = EjabberdApiClient.new
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
field :nostr_discovery_relays, type: :array, default: %w[
|
|
||||||
wss://nostr.kosmos.org
|
|
||||||
wss://purplepag.es
|
|
||||||
wss://relay.nostr.band
|
|
||||||
wss://njump.me
|
|
||||||
wss://relay.damus.io
|
|
||||||
]
|
|
||||||
|
|
||||||
def self.nostr_relay_url_http
|
|
||||||
self.nostr_relay_url.gsub(/^ws:/, "http:")
|
|
||||||
.gsub(/^wss:/, "https:")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
module Settings
|
|
||||||
module OpenCollectiveSettings
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
included do
|
|
||||||
field :opencollective_enabled, type: :boolean, default: true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -2,30 +2,226 @@
|
|||||||
class Setting < RailsSettings::Base
|
class Setting < RailsSettings::Base
|
||||||
cache_prefix { "v1" }
|
cache_prefix { "v1" }
|
||||||
|
|
||||||
Dir[Rails.root.join('app', 'models', 'concerns', 'settings', '*.rb')].each do |file|
|
field :primary_domain, type: :string,
|
||||||
require file
|
default: ENV["PRIMARY_DOMAIN"].presence
|
||||||
end
|
|
||||||
|
|
||||||
include Settings::GeneralSettings
|
field :accounts_domain, type: :string,
|
||||||
include Settings::BtcpaySettings
|
default: ENV["AKKOUNTS_DOMAIN"].presence
|
||||||
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
|
# Internal services
|
||||||
known_services.select {|s| Setting.send "#{s}_enabled?" }
|
#
|
||||||
end
|
|
||||||
|
|
||||||
field :default_services, type: :array,
|
field :redis_url, type: :string,
|
||||||
default: self.available_services
|
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 xmpp ]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -180,14 +180,14 @@ class User < ApplicationRecord
|
|||||||
def enable_service(service)
|
def enable_service(service)
|
||||||
current_services = services_enabled
|
current_services = services_enabled
|
||||||
new_services = Array(service).map(&:to_s)
|
new_services = Array(service).map(&:to_s)
|
||||||
services = (current_services + new_services).uniq.sort
|
services = (current_services + new_services).uniq
|
||||||
ldap.replace_attribute(dn, :serviceEnabled, services)
|
ldap.replace_attribute(dn, :serviceEnabled, services)
|
||||||
end
|
end
|
||||||
|
|
||||||
def disable_service(service)
|
def disable_service(service)
|
||||||
current_services = services_enabled
|
current_services = services_enabled
|
||||||
disabled_services = Array(service).map(&:to_s)
|
disabled_services = Array(service).map(&:to_s)
|
||||||
services = (current_services - disabled_services).uniq.sort
|
services = (current_services - disabled_services).uniq
|
||||||
ldap.replace_attribute(dn, :serviceEnabled, services)
|
ldap.replace_attribute(dn, :serviceEnabled, services)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
module NostrManager
|
|
||||||
class DiscoverUserProfile < NostrManagerService
|
|
||||||
def initialize(pubkey:, relays: nil)
|
|
||||||
@pubkey = pubkey
|
|
||||||
@relays = relays.present? ? relays : Setting.nostr_discovery_relays
|
|
||||||
end
|
|
||||||
|
|
||||||
def call
|
|
||||||
filter = Nostr::Filter.new(
|
|
||||||
authors: [@pubkey],
|
|
||||||
kinds: [0],
|
|
||||||
limit: 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
NostrManager::FetchLatestEvent.call(
|
|
||||||
relays: @relays,
|
|
||||||
filter: filter
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
module NostrManager
|
|
||||||
class DiscoverUserRelays < NostrManagerService
|
|
||||||
def initialize(pubkey:)
|
|
||||||
@pubkey = pubkey
|
|
||||||
@relays = Setting.nostr_discovery_relays
|
|
||||||
end
|
|
||||||
|
|
||||||
def call
|
|
||||||
filter = Nostr::Filter.new(
|
|
||||||
authors: [@pubkey],
|
|
||||||
kinds: [10002],
|
|
||||||
limit: 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
NostrManager::FetchLatestEvent.call(
|
|
||||||
relays: @relays,
|
|
||||||
filter: filter
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
module NostrManager
|
|
||||||
class FetchEvent < NostrManagerService
|
|
||||||
TIMEOUT = 10
|
|
||||||
|
|
||||||
def initialize(filter:, relay_url:)
|
|
||||||
@filter = filter
|
|
||||||
@relay = new_relay(relay_url)
|
|
||||||
@client = Nostr::Client.new
|
|
||||||
end
|
|
||||||
|
|
||||||
def call
|
|
||||||
filter, client, relay = @filter, @client, @relay
|
|
||||||
event = nil
|
|
||||||
mutex = Mutex.new
|
|
||||||
received_event = ConditionVariable.new
|
|
||||||
log_prefix = "[nostr][#{@relay.name}]"
|
|
||||||
|
|
||||||
thread = Thread.new do
|
|
||||||
client.on :connect do
|
|
||||||
client.subscribe(filter: filter)
|
|
||||||
end
|
|
||||||
|
|
||||||
client.on :error do |e|
|
|
||||||
Rails.logger.info "#{log_prefix} Error: #{e}"
|
|
||||||
Thread.current.exit
|
|
||||||
end
|
|
||||||
|
|
||||||
client.on :message do |m|
|
|
||||||
msg = JSON.parse(m) rescue nil
|
|
||||||
if msg && msg[0] == "EVENT" && msg[2]
|
|
||||||
Rails.logger.debug "#{log_prefix} Event received: #{msg[2]["id"]}"
|
|
||||||
mutex.synchronize do
|
|
||||||
event = msg[2]
|
|
||||||
received_event.signal
|
|
||||||
end
|
|
||||||
elsif msg && msg[0] == "EOSE"
|
|
||||||
Thread.current.exit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
client.connect relay
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
|
||||||
Timeout.timeout(TIMEOUT) do
|
|
||||||
mutex.synchronize do
|
|
||||||
received_event.wait(mutex) if event.nil?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
rescue Timeout::Error
|
|
||||||
Rails.logger.debug "#{log_prefix} Timeout: No event received within #{TIMEOUT} seconds"
|
|
||||||
ensure
|
|
||||||
thread.exit
|
|
||||||
end
|
|
||||||
|
|
||||||
event
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
module NostrManager
|
|
||||||
class FetchLatestEvent < NostrManagerService
|
|
||||||
TIMEOUT = 20
|
|
||||||
|
|
||||||
def initialize(relays:, filter:, max_events: 2)
|
|
||||||
@relays = relays
|
|
||||||
@filter = filter
|
|
||||||
@max_events = max_events
|
|
||||||
end
|
|
||||||
|
|
||||||
def call
|
|
||||||
received_events = 0
|
|
||||||
events = []
|
|
||||||
|
|
||||||
begin
|
|
||||||
Timeout.timeout(TIMEOUT) do
|
|
||||||
@relays.each do |url|
|
|
||||||
event = NostrManager::FetchEvent.call(filter: @filter, relay_url: url)
|
|
||||||
|
|
||||||
if event.present?
|
|
||||||
events << event if events.none? { |e| e["id"] == event["id"] }
|
|
||||||
received_events += 1
|
|
||||||
end
|
|
||||||
|
|
||||||
if received_events >= @max_events
|
|
||||||
Rails.logger.debug "Found #{@max_events} events, ending the search"
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
events.min_by { |e| e["created_at"] }
|
|
||||||
end
|
|
||||||
rescue Timeout::Error
|
|
||||||
if events.size == 1
|
|
||||||
Rails.logger.debug "[nostr] Timeout: only found 1 event within #{TIMEOUT} seconds for filter: #{@filter.inspect}"
|
|
||||||
events.first
|
|
||||||
else
|
|
||||||
Rails.logger.debug "[nostr] Timeout: no events found within #{TIMEOUT} seconds for filter: #{@filter.inspect}"
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -19,28 +19,28 @@ module NostrManager
|
|||||||
|
|
||||||
thread = Thread.new do
|
thread = Thread.new do
|
||||||
client.on :connect do
|
client.on :connect do
|
||||||
Rails.logger.debug "#{log_prefix} Publishing #{event.id}..."
|
puts "#{log_prefix} Publishing #{event.id}..."
|
||||||
client.publish event
|
client.publish event
|
||||||
end
|
end
|
||||||
|
|
||||||
client.on :error do |e|
|
client.on :error do |e|
|
||||||
Rails.logger.debug "#{log_prefix} Error: #{e}"
|
puts "#{log_prefix} Error: #{e}"
|
||||||
Rails.logger.debug "#{log_prefix} Closing thread..."
|
puts "#{log_prefix} Closing thread..."
|
||||||
thread.exit
|
thread.exit
|
||||||
end
|
end
|
||||||
|
|
||||||
client.on :message do |m|
|
client.on :message do |m|
|
||||||
Rails.logger.debug "#{log_prefix} Message: #{m}"
|
puts "#{log_prefix} Message: #{m}"
|
||||||
msg = JSON.parse(m) rescue []
|
msg = JSON.parse(m) rescue []
|
||||||
if msg[0] == "OK" && msg[1] == event.id && msg[2]
|
if msg[0] == "OK" && msg[1] == event.id && msg[2]
|
||||||
Rails.logger.debug "#{log_prefix} Event published. Closing thread..."
|
puts "#{log_prefix} Event published. Closing thread..."
|
||||||
else
|
else
|
||||||
Rails.logger.debug "#{log_prefix} Unexpected message from relay. Closing thread..."
|
puts "#{log_prefix} Unexpected message from relay. Closing thread..."
|
||||||
end
|
end
|
||||||
thread.exit
|
thread.exit
|
||||||
end
|
end
|
||||||
|
|
||||||
Rails.logger.debug "#{log_prefix} Connecting to #{relay.url}..."
|
puts "#{log_prefix} Connecting to #{relay.url}..."
|
||||||
client.connect relay
|
client.connect relay
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ require "nostr"
|
|||||||
class NostrManagerService < ApplicationService
|
class NostrManagerService < ApplicationService
|
||||||
def parse_tags(tags)
|
def parse_tags(tags)
|
||||||
out = {}
|
out = {}
|
||||||
# TODO support more than 1 item for each tag type
|
|
||||||
tags.each do |tag|
|
tags.each do |tag|
|
||||||
out[tag[0].to_sym] = tag[1, tag.length]
|
out[tag[0].to_sym] = tag[1, tag.length]
|
||||||
end
|
end
|
||||||
@@ -20,8 +19,4 @@ class NostrManagerService < ApplicationService
|
|||||||
def site_user
|
def site_user
|
||||||
Nostr::User.new(keypair: site_keypair)
|
Nostr::User.new(keypair: site_keypair)
|
||||||
end
|
end
|
||||||
|
|
||||||
def new_relay(url)
|
|
||||||
Nostr::Relay.new(url: url, name: URI.parse(url).host)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,36 +9,18 @@
|
|||||||
<%= render partial: "admin/settings/errors", locals: { errors: @errors } %>
|
<%= render partial: "admin/settings/errors", locals: { errors: @errors } %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<ul role="list">
|
<label class="block">
|
||||||
<%= render FormElements::FieldsetComponent.new(
|
<p class="font-bold mb-1">Reserved usernames</p>
|
||||||
title: "Reserved usernames",
|
<p class="text-gray-500">
|
||||||
description: "These usernames cannot be registered as accounts."
|
These usernames cannot be registered as accounts:
|
||||||
) do %>
|
</p>
|
||||||
<%= f.text_area :reserved_usernames,
|
<%= f.text_area :reserved_usernames,
|
||||||
value: Setting.reserved_usernames.join("\n"),
|
value: Setting.reserved_usernames.join("\n"),
|
||||||
class: "h-44 w-60" %>
|
class: "h-44 mb-2" %>
|
||||||
<p class="text-sm text-gray-500">
|
<p class="text-sm text-gray-500">
|
||||||
One username per line
|
One username per line
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
</label>
|
||||||
<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>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
|||||||
@@ -19,11 +19,6 @@
|
|||||||
title: "Public key",
|
title: "Public key",
|
||||||
description: "The corresponding public key of the accounts service"
|
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(
|
<%= render FormElements::FieldsetResettableSettingComponent.new(
|
||||||
key: :nostr_relay_url,
|
key: :nostr_relay_url,
|
||||||
title: "Relay URL",
|
title: "Relay URL",
|
||||||
@@ -31,28 +26,13 @@
|
|||||||
) %>
|
) %>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h3>Zaps</h3>
|
<h3>Zaps</h3>
|
||||||
<ul role="list">
|
<ul role="list">
|
||||||
<%= render FormElements::FieldsetResettableSettingComponent.new(
|
<%= render FormElements::FieldsetResettableSettingComponent.new(
|
||||||
key: :nostr_zaps_relay_limit,
|
key: :nostr_zaps_relay_limit,
|
||||||
title: "Relay limit",
|
title: "Relay limit",
|
||||||
description: "The maximum number of sender-defined relays to try to publish zap receipts to"
|
description: "The maximum number of relays to publish zap receipts to"
|
||||||
) %>
|
) %>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h3>Onboarding</h3>
|
|
||||||
<ul role="list">
|
|
||||||
<%= render FormElements::FieldsetComponent.new(
|
|
||||||
title: "Discovery relays",
|
|
||||||
description: "Used to discover a user's published relay list and/or profile"
|
|
||||||
) do %>
|
|
||||||
<%= f.text_area :nostr_discovery_relays,
|
|
||||||
value: Setting.nostr_discovery_relays.join("\n"),
|
|
||||||
class: "h-44 w-80" %>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<h3>RemoteStorage</h3>
|
<h3>RemoteStorage</h3>
|
||||||
|
<p class="text-red-600 mb-8">Feature currently in development.</p>
|
||||||
<ul role="list">
|
<ul role="list">
|
||||||
<%= render FormElements::FieldsetToggleComponent.new(
|
<%= render FormElements::FieldsetToggleComponent.new(
|
||||||
form: f,
|
form: f,
|
||||||
|
|||||||
@@ -184,7 +184,7 @@
|
|||||||
<td>XMPP (ejabberd)</td>
|
<td>XMPP (ejabberd)</td>
|
||||||
<td>
|
<td>
|
||||||
<%= render FormElements::ToggleComponent.new(
|
<%= render FormElements::ToggleComponent.new(
|
||||||
enabled: @services_enabled.include?("ejabberd"),
|
enabled: @services_enabled.include?("xmpp"),
|
||||||
input_enabled: false
|
input_enabled: false
|
||||||
) %>
|
) %>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -14,8 +14,7 @@
|
|||||||
<p class="mb-6">
|
<p class="mb-6">
|
||||||
In order to connect an app to your storage account, give it your address:
|
In order to connect an app to your storage account, give it your address:
|
||||||
</p>
|
</p>
|
||||||
<p data-controller="clipboard" class="flex items-center gap-1 sm:w-2/5">
|
<p data-controller="clipboard" class="flex gap-1 sm:w-2/5">
|
||||||
<img src="/img/logos/icon_remotestorage.svg" class="inline-block h-6 w-6 mr-1">
|
|
||||||
<input type="text" id="user_address" class="grow"
|
<input type="text" id="user_address" class="grow"
|
||||||
value=<%= current_user.address %> disabled="disabled"
|
value=<%= current_user.address %> disabled="disabled"
|
||||||
data-clipboard-target="source" />
|
data-clipboard-target="source" />
|
||||||
@@ -32,24 +31,6 @@
|
|||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
|
||||||
<h3>Compatible Apps</h3>
|
|
||||||
<p>
|
|
||||||
Your Storage account is based on a new open standard called
|
|
||||||
<a href="https://remotestorage.io" target="_blank">
|
|
||||||
<img src="/img/logos/icon_remotestorage.svg" class="h-4 w-4 inline">
|
|
||||||
<strong>remoteStorage</strong>
|
|
||||||
</a>, which is not yet widely supported. Look
|
|
||||||
for the remoteStorage icon, or check the Sync settings in apps.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
If you want your favorite apps to support syncing data with your own
|
|
||||||
Storage account, let the developers know! All relevant information is
|
|
||||||
available on the <a href="https://remotestorage.io"
|
|
||||||
target="_blank" class="ks-text-link">remoteStorage website</a>.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h3>Recommended Apps</h3>
|
<h3>Recommended Apps</h3>
|
||||||
<div data-controller="tabs"
|
<div data-controller="tabs"
|
||||||
|
|||||||
@@ -1,43 +1,47 @@
|
|||||||
|
<section>
|
||||||
|
<h3>Nostr</h3>
|
||||||
|
<h4 class="mb-0">Public Key</h4>
|
||||||
<div data-controller="settings--nostr-pubkey"
|
<div data-controller="settings--nostr-pubkey"
|
||||||
data-settings--nostr-pubkey-user-address-value="<%= current_user.address %>"
|
data-settings--nostr-pubkey-user-address-value="<%= current_user.address %>"
|
||||||
data-settings--nostr-pubkey-site-value="<%= Setting.accounts_domain %>"
|
data-settings--nostr-pubkey-site-value="<%= Setting.accounts_domain %>"
|
||||||
data-settings--nostr-pubkey-shared-secret-value="<%= session[:shared_secret] %>"
|
data-settings--nostr-pubkey-shared-secret-value="<%= session[:shared_secret] %>"
|
||||||
data-settings--nostr-pubkey-pubkey-hex-value="<%= current_user.nostr_pubkey %>">
|
data-settings--nostr-pubkey-pubkey-hex-value="<%= current_user.nostr_pubkey %>">
|
||||||
<section class="mb-8 sm:mb-12">
|
|
||||||
<h3>Nostr</h3>
|
<p class="<%= current_user.nostr_pubkey.present? ? '' : 'hidden' %> mt-2 flex gap-1">
|
||||||
<h4 class="mb-0">
|
|
||||||
Public Key
|
|
||||||
</h4>
|
|
||||||
<p class="<%= current_user.nostr_pubkey.present? ? '' : 'hidden' %> mt-2 flex gap-x-1">
|
|
||||||
<input type="text" value="<%= current_user.nostr_pubkey_bech32 %>" disabled
|
<input type="text" value="<%= current_user.nostr_pubkey_bech32 %>" disabled
|
||||||
data-settings--nostr-pubkey-target="pubkeyBech32Input"
|
data-settings--nostr-pubkey-target="pubkeyBech32Input"
|
||||||
name="nostr_public_key" class="w-full" />
|
name="nostr_public_key" class="relative grow" />
|
||||||
<%= link_to nostr_pubkey_settings_path,
|
<%= link_to nostr_pubkey_settings_path,
|
||||||
class: 'btn-md btn-outline relative grow-0 shrink-0 text-red-700',
|
class: 'btn-md btn-outline text-red-700 relative shrink-0',
|
||||||
data: { turbo_method: :delete, turbo_confirm: 'Are you sure?' } do %>
|
data: { turbo_method: :delete, turbo_confirm: 'Are you sure?' } do %>
|
||||||
Remove
|
Remove
|
||||||
<% end %>
|
<% end %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<% if current_user.nostr_pubkey.present? %>
|
<% if current_user.nostr_pubkey.present? %>
|
||||||
<!-- <div> -->
|
<div class="rounded-md bg-blue-50 p-4">
|
||||||
<!-- Pubkey present -->
|
<div class="flex">
|
||||||
<!-- </div> -->
|
<div class="flex-shrink-0">
|
||||||
|
<svg class="h-5 w-5 text-blue-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
|
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="ml-3 flex-1">
|
||||||
|
<p class="text-sm text-blue-800">
|
||||||
|
Your user address <strong><%= current_user.address %></strong> is
|
||||||
|
also a Nostr address now. Use your favorite Nostr app, or for
|
||||||
|
example <a href="http://metadata.nostr.com" target="_blank"
|
||||||
|
class="underline">metadata.nostr.com</a>, to add this
|
||||||
|
<strong>NIP-05</strong> address to your public profile.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<% else %>
|
<% else %>
|
||||||
<p class="my-4">
|
<p class="my-4">
|
||||||
Verify your Nostr public key with us in order to enable Nostr-specific
|
If you use any apps on the Nostr network, you can verify your public key
|
||||||
features for your account:
|
with us in order to enable Nostr-specific features for your account.
|
||||||
</p>
|
</p>
|
||||||
<ul class="list-disc list-inside">
|
|
||||||
<li>Log in with Nostr (no password needed)</li>
|
|
||||||
<li>Verified Nostr address</li>
|
|
||||||
<% if Setting.lndhub_enabled? %>
|
|
||||||
<li>Receive zaps in your Lightning account</li>
|
|
||||||
<% end %>
|
|
||||||
<% if Setting.nostr_relay_url.present? %>
|
|
||||||
<li>Publish notes on <%= link_to "our relay", Setting.nostr_relay_url_http, class: "ks-text-link", target: "_blank" %></li>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<div data-settings--nostr-pubkey-target="noExtension"
|
<div data-settings--nostr-pubkey-target="noExtension"
|
||||||
@@ -54,8 +58,8 @@
|
|||||||
</h3>
|
</h3>
|
||||||
<div class="mt-2 mb-0 text-sm text-blue-800">
|
<div class="mt-2 mb-0 text-sm text-blue-800">
|
||||||
<p>
|
<p>
|
||||||
We recommend Alby, which you can also use a wallet for your
|
We recommend Alby, which you can also use for your Lightning
|
||||||
Lightning account.
|
Wallet.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
@@ -82,11 +86,5 @@
|
|||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</section>
|
|
||||||
|
|
||||||
<% if current_user.nostr_pubkey.present? %>
|
|
||||||
<%= turbo_frame_tag "nostr_user_metadata", src: nostr_user_metadata_settings_path do %>
|
|
||||||
<p>Loading...</p>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
<%= turbo_frame_tag "nostr_user_metadata" do %>
|
|
||||||
<section>
|
|
||||||
<h3>Relays</h3>
|
|
||||||
<%= render Settings::NostrRelayStatusComponent.new(
|
|
||||||
nip65_event: @nip65_event
|
|
||||||
) %>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h3>Profile</h3>
|
|
||||||
<%= render Settings::NostrProfileStatusComponent.new(
|
|
||||||
profile_event: @profile,
|
|
||||||
user_address: current_user.address
|
|
||||||
) %>
|
|
||||||
<div class="mt-8" data-controller="modal" data-action="keydown.esc->modal#close">
|
|
||||||
<button data-action="click->modal#open" class="btn-md btn-blue w-full sm:w-auto">
|
|
||||||
Edit profile
|
|
||||||
</button>
|
|
||||||
<%= render ModalComponent.new(show_close_button: false) do %>
|
|
||||||
<%= render Settings::NostrEditProfileComponent.new(
|
|
||||||
user: current_user,
|
|
||||||
profile_event: @profile
|
|
||||||
) %>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<% end %>
|
|
||||||
@@ -19,6 +19,12 @@
|
|||||||
active: @settings_section.to_s == "email"
|
active: @settings_section.to_s == "email"
|
||||||
) %>
|
) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<% if Setting.lndhub_enabled %>
|
||||||
|
<%= render SidenavLinkComponent.new(
|
||||||
|
name: "Lightning", path: setting_path(:lightning), icon: "zap",
|
||||||
|
active: @settings_section.to_s == "lightning"
|
||||||
|
) %>
|
||||||
|
<% end %>
|
||||||
<% if Setting.remotestorage_enabled? &&
|
<% if Setting.remotestorage_enabled? &&
|
||||||
Flipper.enabled?(:remotestorage, current_user) %>
|
Flipper.enabled?(:remotestorage, current_user) %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
@@ -26,12 +32,6 @@
|
|||||||
active: @settings_section.to_s == "remotestorage"
|
active: @settings_section.to_s == "remotestorage"
|
||||||
) %>
|
) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if Setting.lndhub_enabled %>
|
|
||||||
<%= render SidenavLinkComponent.new(
|
|
||||||
name: "Lightning", path: setting_path(:lightning), icon: "zap",
|
|
||||||
active: @settings_section.to_s == "lightning"
|
|
||||||
) %>
|
|
||||||
<% end %>
|
|
||||||
<% if Setting.nostr_enabled %>
|
<% if Setting.nostr_enabled %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
name: "Nostr", path: setting_path(:nostr), icon: "nostrich-head",
|
name: "Nostr", path: setting_path(:nostr), icon: "nostrich-head",
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
<div>
|
|
||||||
<%= profile.inspect %>
|
|
||||||
</div>
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
config_path = Rails.root.join('config', 'services.yml')
|
|
||||||
SERVICES = YAML.load_file(config_path).deep_symbolize_keys.with_indifferent_access
|
|
||||||
@@ -65,7 +65,6 @@ Rails.application.routes.draw do
|
|||||||
post 'reset_email_password'
|
post 'reset_email_password'
|
||||||
post 'set_nostr_pubkey'
|
post 'set_nostr_pubkey'
|
||||||
delete 'nostr_pubkey', to: 'settings#remove_nostr_pubkey'
|
delete 'nostr_pubkey', to: 'settings#remove_nostr_pubkey'
|
||||||
get 'fetch_nostr_user_metadata', as: 'nostr_user_metadata'
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
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
|
|
||||||
29
doc/integrations/strfry.md
Normal file
29
doc/integrations/strfry.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# strfry (nostr relay)
|
||||||
|
|
||||||
|
## LDAP policy
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
## Useful scripts
|
||||||
|
|
||||||
|
### Syncing events for all local nostr users from a remote relay
|
||||||
|
|
||||||
|
You can sync all events of all local users with a pubkey stored in LDAP from a
|
||||||
|
specified remote relay to the local relay with the `strfry-sync.ts` script:
|
||||||
|
|
||||||
|
deno run -A /opt/strfry-sync.ts wss://relay.example.com
|
||||||
|
|
||||||
|
Doing the same with Docker Compose (great for seeding data to your local relay
|
||||||
|
in development):
|
||||||
|
|
||||||
|
docker compose run strfry deno run -A /opt/strfry-sync.ts wss://relay.example.com
|
||||||
|
|
||||||
|
## Docker image
|
||||||
|
|
||||||
|
In order to use the LDAP policy with Docker, you will need
|
||||||
|
[Deno](https://deno.com/) installed in your strfry container. We provide a
|
||||||
|
custom Docker image for strfry with Deno included (which we use in
|
||||||
|
development):
|
||||||
|
|
||||||
|
* Registry: https://gitea.kosmos.org/kosmos/-/packages/container/strfry-deno/1.1.1
|
||||||
|
* Source: https://github.com/raucao/strfry/blob/docker_deno/ubuntu.Dockerfile
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
"postcss-preset-env": "^7.8.3",
|
"postcss-preset-env": "^7.8.3",
|
||||||
"tailwindcss": "^3.2.4"
|
"tailwindcss": "^3.2.4"
|
||||||
},
|
},
|
||||||
"version": "0.10.0",
|
"version": "0.9.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:css:tailwind": "tailwindcss --postcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css",
|
"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"
|
"build:css": "yarn run build:css:tailwind"
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -44,7 +44,7 @@ RSpec.describe CreateLdapUserJob, type: :job do
|
|||||||
|
|
||||||
it "adds default services for pre-confirmed accounts" do
|
it "adds default services for pre-confirmed accounts" do
|
||||||
allow(ldap_client_mock).to receive(:add) # spy on mock
|
allow(ldap_client_mock).to receive(:add) # spy on mock
|
||||||
Setting.default_services = ["ejabberd", "discourse"]
|
allow(Setting).to receive(:default_services).and_return(["xmpp", "discourse"])
|
||||||
|
|
||||||
perform_enqueued_jobs { job_for_preconfirmed_account }
|
perform_enqueued_jobs { job_for_preconfirmed_account }
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ RSpec.describe CreateLdapUserJob, type: :job do
|
|||||||
sn: "halfinney",
|
sn: "halfinney",
|
||||||
uid: "halfinney",
|
uid: "halfinney",
|
||||||
mail: "halfinney@example.com",
|
mail: "halfinney@example.com",
|
||||||
serviceEnabled: ["ejabberd", "discourse"],
|
serviceEnabled: ["xmpp", "discourse"],
|
||||||
userPassword: "remember-remember-the-5th-of-november"
|
userPassword: "remember-remember-the-5th-of-november"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ RSpec.describe XmppExchangeContactsJob, type: :job do
|
|||||||
before do
|
before do
|
||||||
stub_request(:post, "http://xmpp.example.com/api/add_rosteritem")
|
stub_request(:post, "http://xmpp.example.com/api/add_rosteritem")
|
||||||
.to_return(status: 200, body: "", headers: {})
|
.to_return(status: 200, body: "", headers: {})
|
||||||
allow_any_instance_of(User).to receive(:services_enabled).and_return(["ejabberd"])
|
allow_any_instance_of(User).to receive(:services_enabled).and_return(["xmpp"])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "posts add_rosteritem commands to the ejabberd API" do
|
it "posts add_rosteritem commands to the ejabberd API" do
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -78,9 +78,9 @@ RSpec.describe User, type: :model do
|
|||||||
it "returns the entries from the LDAP service attribute" do
|
it "returns the entries from the LDAP service attribute" do
|
||||||
expect(user).to receive(:ldap_entry).and_return({
|
expect(user).to receive(:ldap_entry).and_return({
|
||||||
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
||||||
services_enabled: ["discourse", "ejabberd", "email", "gitea", "wiki"]
|
services_enabled: ["discourse", "email", "gitea", "wiki", "xmpp"]
|
||||||
})
|
})
|
||||||
expect(user.services_enabled).to eq(["discourse", "ejabberd", "email", "gitea", "wiki"])
|
expect(user.services_enabled).to eq(["discourse", "email", "gitea", "wiki", "xmpp"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ RSpec.describe User, type: :model do
|
|||||||
before do
|
before do
|
||||||
allow(user).to receive(:ldap_entry).and_return({
|
allow(user).to receive(:ldap_entry).and_return({
|
||||||
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
||||||
services_enabled: ["ejabberd", "gitea"]
|
services_enabled: ["gitea", "xmpp"]
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -121,9 +121,9 @@ RSpec.describe User, type: :model do
|
|||||||
|
|
||||||
it "adds multiple service to the LDAP entry" do
|
it "adds multiple service to the LDAP entry" do
|
||||||
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
||||||
.with(dn, :serviceEnabled, ["discourse", "ejabberd", "gitea", "wiki"]).and_return(true)
|
.with(dn, :serviceEnabled, ["discourse", "gitea", "wiki", "xmpp"]).and_return(true)
|
||||||
|
|
||||||
user.enable_service([:ejabberd, :wiki])
|
user.enable_service([:wiki, :xmpp])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ RSpec.describe User, type: :model do
|
|||||||
before do
|
before do
|
||||||
allow(user).to receive(:ldap_entry).and_return({
|
allow(user).to receive(:ldap_entry).and_return({
|
||||||
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
||||||
services_enabled: ["discourse", "ejabberd", "gitea"]
|
services_enabled: ["discourse", "gitea", "xmpp"]
|
||||||
})
|
})
|
||||||
allow(user).to receive(:dn).and_return(dn)
|
allow(user).to receive(:dn).and_return(dn)
|
||||||
end
|
end
|
||||||
@@ -140,14 +140,14 @@ RSpec.describe User, type: :model do
|
|||||||
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
||||||
.with(dn, :serviceEnabled, ["discourse", "gitea"]).and_return(true)
|
.with(dn, :serviceEnabled, ["discourse", "gitea"]).and_return(true)
|
||||||
|
|
||||||
user.disable_service(:ejabberd)
|
user.disable_service(:xmpp)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "removes multiple services from the LDAP entry" do
|
it "removes multiple services from the LDAP entry" do
|
||||||
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
||||||
.with(dn, :serviceEnabled, ["discourse"]).and_return(true)
|
.with(dn, :serviceEnabled, ["discourse"]).and_return(true)
|
||||||
|
|
||||||
user.disable_service([:ejabberd, "gitea"])
|
user.disable_service([:xmpp, "gitea"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ RSpec.describe User, type: :model do
|
|||||||
after { clear_enqueued_jobs }
|
after { clear_enqueued_jobs }
|
||||||
|
|
||||||
it "enables default services" do
|
it "enables default services" do
|
||||||
expect(user).to receive(:enable_service).with(Setting.default_services)
|
expect(user).to receive(:enable_service).with(%w[ discourse gitea mastodon mediawiki xmpp ])
|
||||||
user.send :devise_after_confirmation
|
user.send :devise_after_confirmation
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ RSpec.describe "WebFinger", type: :request do
|
|||||||
before do
|
before do
|
||||||
allow_any_instance_of(User).to receive(:ldap_entry).and_return({
|
allow_any_instance_of(User).to receive(:ldap_entry).and_return({
|
||||||
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
||||||
services_enabled: ["ejabberd"]
|
services_enabled: ["xmpp"]
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -92,13 +92,7 @@ RSpec.describe "WebFinger", type: :request do
|
|||||||
expect(rs_link["href"]).to eql("#{Setting.rs_storage_url}/tony")
|
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"]
|
oauth_url = rs_link["properties"]["http://tools.ietf.org/html/rfc6749#section-4.2"]
|
||||||
expect(oauth_url).to eql("http://accounts.kosmos.org/rs/oauth/tony")
|
expect(oauth_url).to eql("http://www.example.com/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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -106,7 +100,7 @@ RSpec.describe "WebFinger", type: :request do
|
|||||||
before do
|
before do
|
||||||
allow_any_instance_of(User).to receive(:ldap_entry).and_return({
|
allow_any_instance_of(User).to receive(:ldap_entry).and_return({
|
||||||
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
||||||
services_enabled: ["ejabberd"]
|
services_enabled: ["xmpp"]
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -46,12 +46,6 @@ RSpec.describe "Well-known URLs", type: :request do
|
|||||||
expect(res["names"]["bobdylan"]).to eq(user.nostr_pubkey)
|
expect(res["names"]["bobdylan"]).to eq(user.nostr_pubkey)
|
||||||
end
|
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
|
context "without relay configured" do
|
||||||
before do
|
before do
|
||||||
Setting.nostr_relay_url = ""
|
Setting.nostr_relay_url = ""
|
||||||
@@ -79,36 +73,10 @@ RSpec.describe "Well-known URLs", type: :request do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe "placeholder username for domain's own pubkey" do
|
describe "placeholder username for domain's own 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("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
|
it "returns the configured nostr pubkey" do
|
||||||
headers = { "X-Forwarded-Host" => "accounts.kosmos.org" }
|
|
||||||
get "/.well-known/nostr.json?name=_"
|
get "/.well-known/nostr.json?name=_"
|
||||||
|
|
||||||
res = JSON.parse(response.body)
|
res = JSON.parse(response.body)
|
||||||
expect(res["names"]["_"]).to eq("bdd76ce2934b2f591f9fad2ebe9da18f20d2921de527494ba00eeaa0a0efadcf")
|
expect(res["names"]["_"]).to eq(Setting.nostr_public_key)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with relay configured" do
|
context "with relay configured" do
|
||||||
|
|||||||
Reference in New Issue
Block a user