Compare commits
35 Commits
560f193c4b
...
docs/integ
| Author | SHA1 | Date | |
|---|---|---|---|
|
14c5dd22d6
|
|||
|
f3676949d2
|
|||
|
79952b73c5
|
|||
| 17c419403e | |||
|
6d06312a5c
|
|||
|
acb399b0b7
|
|||
|
bf20b6467e
|
|||
|
b91d90d75c
|
|||
|
3284bbf6ca
|
|||
|
171b84ee81
|
|||
|
54b01dd282
|
|||
| 32dff9c67f | |||
|
126b8b20e0
|
|||
|
5abf69f356
|
|||
|
210a69bd9b
|
|||
|
bbed3cd367
|
|||
|
7943da0f17
|
|||
| 620167eedf | |||
|
e077debfc2
|
|||
|
531b2c3002
|
|||
|
6d2bc729b8
|
|||
|
2630ec2af4
|
|||
| daed5c1eea | |||
| 2e9429bb32 | |||
|
37c15c7a62
|
|||
|
01ecea74ff
|
|||
|
f401a03590
|
|||
|
48ab96dda9
|
|||
|
7ac3130c18
|
|||
|
cbfa148051
|
|||
|
87d900b627
|
|||
|
926dc06294
|
|||
|
00b73b06d7
|
|||
|
0daac33915
|
|||
|
0e472bc311
|
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#
|
#
|
||||||
# Service Integrations
|
# Service Integrations
|
||||||
|
# (sorted alphabetically by service name)
|
||||||
#
|
#
|
||||||
|
|
||||||
# BTCPAY_PUBLIC_URL='https://btcpay.example.com'
|
# BTCPAY_PUBLIC_URL='https://btcpay.example.com'
|
||||||
@@ -62,5 +63,9 @@
|
|||||||
|
|
||||||
# MEDIAWIKI_PUBLIC_URL='https://wiki.kosmos.org'
|
# MEDIAWIKI_PUBLIC_URL='https://wiki.kosmos.org'
|
||||||
|
|
||||||
|
# NOSTR_PRIVATE_KEY='123456abcdef...'
|
||||||
|
# NOSTR_PUBLIC_KEY='123456abcdef...'
|
||||||
|
# NOSTR_RELAY_URL='wss://nostr.kosmos.org'
|
||||||
|
|
||||||
# RS_STORAGE_URL='https://storage.kosmos.org'
|
# RS_STORAGE_URL='https://storage.kosmos.org'
|
||||||
# RS_REDIS_URL='redis://localhost:6379/2'
|
# RS_REDIS_URL='redis://localhost:6379/2'
|
||||||
|
|||||||
2
Gemfile
@@ -61,7 +61,7 @@ gem "sentry-rails"
|
|||||||
# Services
|
# Services
|
||||||
gem 'discourse_api'
|
gem 'discourse_api'
|
||||||
gem "lnurl"
|
gem "lnurl"
|
||||||
gem 'manifique'
|
gem 'manifique', '~> 1.1.0'
|
||||||
gem 'nostr', '~> 0.6.0'
|
gem 'nostr', '~> 0.6.0'
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ GEM
|
|||||||
net-imap
|
net-imap
|
||||||
net-pop
|
net-pop
|
||||||
net-smtp
|
net-smtp
|
||||||
manifique (1.0.1)
|
manifique (1.1.0)
|
||||||
faraday (~> 2.9.0)
|
faraday (~> 2.9.0)
|
||||||
faraday-follow_redirects (= 0.3.0)
|
faraday-follow_redirects (= 0.3.0)
|
||||||
nokogiri (~> 1.16.0)
|
nokogiri (~> 1.16.0)
|
||||||
@@ -515,7 +515,7 @@ DEPENDENCIES
|
|||||||
listen (~> 3.2)
|
listen (~> 3.2)
|
||||||
lnurl
|
lnurl
|
||||||
lockbox
|
lockbox
|
||||||
manifique
|
manifique (~> 1.1.0)
|
||||||
net-ldap
|
net-ldap
|
||||||
nostr (~> 0.6.0)
|
nostr (~> 0.6.0)
|
||||||
pagy (~> 6.0, >= 6.0.2)
|
pagy (~> 6.0, >= 6.0.2)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@layer components {
|
@layer components {
|
||||||
.services > div > a {
|
.services > div > a {
|
||||||
background-image: linear-gradient(110deg, rgba(255,255,255,0.99) 0, rgba(255,255,255,0.88) 100%);
|
background-image: linear-gradient(110deg, rgba(255,255,255,0.99) 20%, rgba(255,255,255,0.88) 100%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ class Services::RemotestorageController < Services::BaseController
|
|||||||
# unless current_user.service_enabled?(:remotestorage)
|
# unless current_user.service_enabled?(:remotestorage)
|
||||||
# redirect_to service_remotestorage_info_path
|
# redirect_to service_remotestorage_info_path
|
||||||
# end
|
# end
|
||||||
@rs_auths = current_user.remote_storage_authorizations
|
# @rs_apps_connected = current_user.remote_storage_authorizations.any?
|
||||||
# TODO sort by app name
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -3,13 +3,18 @@ class Services::RsAuthsController < Services::BaseController
|
|||||||
before_action :require_feature_enabled
|
before_action :require_feature_enabled
|
||||||
before_action :require_service_available
|
before_action :require_service_available
|
||||||
# before_action :require_service_enabled
|
# before_action :require_service_enabled
|
||||||
before_action :find_rs_auth
|
before_action :find_rs_auth, only: [:destroy, :launch_app]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@rs_auths = current_user.remote_storage_authorizations
|
||||||
|
# TODO sort by app name?
|
||||||
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@auth.destroy!
|
@auth.destroy!
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do redirect_to services_storage_url, flash: {
|
format.html do redirect_to apps_services_storage_url, flash: {
|
||||||
success: 'App authorization revoked'
|
success: 'App authorization revoked'
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,16 +1,33 @@
|
|||||||
class WellKnownController < ApplicationController
|
class WellKnownController < ApplicationController
|
||||||
|
before_action :require_nostr_enabled, only: [ :nostr ]
|
||||||
|
|
||||||
def nostr
|
def nostr
|
||||||
http_status :unprocessable_entity and return if params[:name].blank?
|
http_status :unprocessable_entity and return if params[:name].blank?
|
||||||
domain = request.headers["X-Forwarded-Host"].presence || Setting.primary_domain
|
domain = request.headers["X-Forwarded-Host"].presence || Setting.primary_domain
|
||||||
|
relay_url = Setting.nostr_relay_url.presence
|
||||||
|
|
||||||
|
if params[:name] == "_"
|
||||||
|
# pubkey for the primary domain without a username (e.g. kosmos.org)
|
||||||
|
res = { names: { "_": Setting.nostr_public_key } }
|
||||||
|
res[:relays] = { "_" => [ relay_url ] } if relay_url
|
||||||
|
else
|
||||||
@user = User.where(cn: params[:name], ou: domain).first
|
@user = User.where(cn: params[:name], ou: domain).first
|
||||||
http_status :not_found and return if @user.nil? || @user.nostr_pubkey.blank?
|
http_status :not_found and return if @user.nil? || @user.nostr_pubkey.blank?
|
||||||
|
|
||||||
|
res = { names: { @user.cn => @user.nostr_pubkey } }
|
||||||
|
res[:relays] = { @user.nostr_pubkey => [ relay_url ] } if relay_url
|
||||||
|
end
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json do
|
format.json do
|
||||||
render json: {
|
render json: res.to_json
|
||||||
names: { "#{@user.cn}": @user.nostr_pubkey }
|
|
||||||
}.to_json
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def require_nostr_enabled
|
||||||
|
http_status :not_found unless Setting.nostr_enabled?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -169,6 +169,9 @@ class Setting < RailsSettings::Base
|
|||||||
field :nostr_public_key, type: :string,
|
field :nostr_public_key, type: :string,
|
||||||
default: ENV["NOSTR_PUBLIC_KEY"].presence
|
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,
|
field :nostr_zaps_relay_limit, type: :integer,
|
||||||
default: 12
|
default: 12
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,13 @@ module NostrManager
|
|||||||
|
|
||||||
def call
|
def call
|
||||||
tags = parse_tags(@zap.request_event.tags)
|
tags = parse_tags(@zap.request_event.tags)
|
||||||
|
relays = tags[:relays].take(Setting.nostr_zaps_relay_limit)
|
||||||
|
|
||||||
tags[:relays].take(Setting.nostr_zaps_relay_limit).each do |relay_url|
|
if Setting.nostr_relay_url.present?
|
||||||
|
relays << Setting.nostr_relay_url
|
||||||
|
end
|
||||||
|
|
||||||
|
relays.uniq.each do |relay_url|
|
||||||
if @delayed
|
if @delayed
|
||||||
NostrPublishEventJob.perform_later(event: @zap.receipt, relay_url: relay_url)
|
NostrPublishEventJob.perform_later(event: @zap.receipt, relay_url: relay_url)
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -38,8 +38,8 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="overflow-ellipsis font-mono"><%= invitation.token %></td>
|
<td class="overflow-ellipsis font-mono"><%= invitation.token %></td>
|
||||||
<td><%= invitation.used_at.strftime("%Y-%m-%d (%H:%M UTC)") %></td>
|
<td><%= invitation.used_at.strftime("%Y-%m-%d (%H:%M UTC)") %></td>
|
||||||
<td><%= link_to invitation.user.address, admin_user_path(invitation.user.address), class: "ks-text-link" %></td>
|
<td><%= link_to invitation.user.cn, admin_user_path(invitation.user.cn), class: "ks-text-link" %></td>
|
||||||
<td><%= link_to invitation.invitee.address, admin_user_path(invitation.invitee.address), class: "ks-text-link" %></td>
|
<td><%= link_to invitation.invitee.cn, admin_user_path(invitation.invitee.cn), class: "ks-text-link" %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<% if user = @users.find{ |u| u[2] == account.login } %>
|
<% if user = @users.find{ |u| u[2] == account.login } %>
|
||||||
<%= link_to "#{user[0]}@#{user[1]}", admin_user_path("#{user[0]}@#{user[1]}"), class: "ks-text-link" %>
|
<%= link_to user[0], admin_user_path(user[0]), class: "ks-text-link" %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</td>
|
</td>
|
||||||
<td><%= number_with_delimiter account.balance.to_i.to_s %></td>
|
<td><%= number_with_delimiter account.balance.to_i.to_s %></td>
|
||||||
|
|||||||
@@ -19,6 +19,11 @@
|
|||||||
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_relay_url,
|
||||||
|
title: "Relay URL",
|
||||||
|
description: "Websockets URL of a relay associated with #{Setting.primary_domain}"
|
||||||
|
) %>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<th>Invited by</th>
|
<th>Invited by</th>
|
||||||
<td>
|
<td>
|
||||||
<% if @user.inviter %>
|
<% if @user.inviter %>
|
||||||
<%= link_to @user.inviter.address, admin_user_path(@user.inviter.address), class: 'ks-text-link' %>
|
<%= link_to @user.inviter.cn, admin_user_path(@user.inviter.cn), class: 'ks-text-link' %>
|
||||||
<% else %>—<% end %>
|
<% else %>—<% end %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
<% if @user.invitees.length > 0 %>
|
<% if @user.invitees.length > 0 %>
|
||||||
<ul class="mb-0">
|
<ul class="mb-0">
|
||||||
<% @user.invitees.order(cn: :asc).each do |invitee| %>
|
<% @user.invitees.order(cn: :asc).each do |invitee| %>
|
||||||
<li class="leading-none mb-2 last:mb-0"><%= link_to invitee.address, admin_user_path(invitee.address), class: 'ks-text-link' %></li>
|
<li class="leading-none mb-2 last:mb-0"><%= link_to invitee.cn, admin_user_path(invitee.cn), class: 'ks-text-link' %></li>
|
||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
<% else %>—<% end %>
|
<% else %>—<% end %>
|
||||||
@@ -124,6 +124,19 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<% if Setting.email_enabled %>
|
||||||
|
<tr>
|
||||||
|
<td>E-Mail</td>
|
||||||
|
<td>
|
||||||
|
<%= render FormElements::ToggleComponent.new(
|
||||||
|
enabled: Flipper.enabled?(:email, current_user),
|
||||||
|
input_enabled: false
|
||||||
|
) %>
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
<% if Setting.gitea_enabled %>
|
<% if Setting.gitea_enabled %>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Gitea</td>
|
<td>Gitea</td>
|
||||||
@@ -182,6 +195,33 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<% if Setting.nostr_enabled %>
|
||||||
|
<tr>
|
||||||
|
<td>Nostr</td>
|
||||||
|
<td>
|
||||||
|
<%= render FormElements::ToggleComponent.new(
|
||||||
|
enabled: @user.nostr_pubkey.present?,
|
||||||
|
input_enabled: false
|
||||||
|
) %>
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<%= link_to "Open profile", "https://njump.me/#{@user.nostr_pubkey_bech32}", class: "btn-sm btn-gray" %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
<% if Setting.remotestorage_enabled %>
|
||||||
|
<tr>
|
||||||
|
<td>remoteStorage</td>
|
||||||
|
<td>
|
||||||
|
<%= render FormElements::ToggleComponent.new(
|
||||||
|
enabled: Flipper.enabled?(:remotestorage, current_user) && @services_enabled.include?("remotestorage"),
|
||||||
|
input_enabled: false
|
||||||
|
) %>
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
We have run two 6-month trials so far, with the next trial period
|
We have run two 6-month trials so far, with the next trial period
|
||||||
starting sometime in Q2 2024. Watch your email for notifications about it!
|
starting sometime soon. Watch your email for notifications about it!
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<div class="services grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6">
|
<div class="services grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6">
|
||||||
<% if Setting.ejabberd_enabled? %>
|
<% if Setting.ejabberd_enabled? %>
|
||||||
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
||||||
bg-cover bg-[center_top_-50px] bg-no-repeat
|
bg-[length:86%] bg-[center_top_-40px] bg-no-repeat
|
||||||
bg-[url(/img/logos/icon_xmpp.svg)]">
|
bg-[url(/img/logos/icon_xmpp.svg)]">
|
||||||
<%= link_to services_chat_path,
|
<%= link_to services_chat_path,
|
||||||
class: "block h-full px-6 py-6 rounded-md" do %>
|
class: "block h-full px-6 py-6 rounded-md" do %>
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<% if Setting.mastodon_enabled? %>
|
<% if Setting.mastodon_enabled? %>
|
||||||
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
||||||
bg-[length:80%] bg-[right_top_-30px] bg-no-repeat
|
bg-[length:88%] bg-[center_top_-40px] bg-no-repeat
|
||||||
bg-[url(/img/logos/icon_mastodon.svg)]">
|
bg-[url(/img/logos/icon_mastodon.svg)]">
|
||||||
<%= link_to services_mastodon_path, class: "block h-full px-6 py-6 rounded-md" do %>
|
<%= link_to services_mastodon_path, class: "block h-full px-6 py-6 rounded-md" do %>
|
||||||
<h3 class="mb-3.5">Mastodon</h3>
|
<h3 class="mb-3.5">Mastodon</h3>
|
||||||
@@ -30,7 +30,9 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<% if Setting.email_enabled? &&
|
<% if Setting.email_enabled? &&
|
||||||
Flipper.enabled?(:email, current_user) %>
|
Flipper.enabled?(:email, current_user) %>
|
||||||
<div class="border border-gray-300 rounded-md hover:border-gray-400">
|
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
||||||
|
bg-[length:90%] bg-[center_top_-160px] bg-no-repeat
|
||||||
|
bg-[url(/img/logos/icon_mail.svg)]">
|
||||||
<%= link_to services_email_path, class: "block h-full px-6 py-6 rounded-md" do %>
|
<%= link_to services_email_path, class: "block h-full px-6 py-6 rounded-md" do %>
|
||||||
<h3 class="mb-3.5">E-Mail</h3>
|
<h3 class="mb-3.5">E-Mail</h3>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
@@ -39,15 +41,16 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if Setting.discourse_enabled? %>
|
<% if Setting.remotestorage_enabled? &&
|
||||||
|
Flipper.enabled?(:remotestorage, current_user) %>
|
||||||
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
||||||
bg-[length:95%] bg-center bg-no-repeat
|
bg-[length:80%] bg-[center_top_-156px] bg-no-repeat
|
||||||
bg-[url(/img/logos/icon_discourse.svg)]">
|
bg-[url(/img/logos/icon_remotestorage.svg)]">
|
||||||
<%= link_to "#{Setting.discourse_public_url}/session/sso?return_path=/",
|
<%= link_to services_storage_path,
|
||||||
class: "block h-full px-6 py-6 rounded-md" do %>
|
class: "block h-full px-6 py-6 rounded-md" do %>
|
||||||
<h3 class="mb-3.5">Discourse</h3>
|
<h3 class="mb-3.5">Storage</h3>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Kosmos community forums and user support/help site
|
Sync your data between apps and devices
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
@@ -65,21 +68,22 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if Setting.remotestorage_enabled? &&
|
<% if Setting.discourse_enabled? %>
|
||||||
Flipper.enabled?(:remotestorage, current_user) %>
|
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
||||||
<div class="border border-gray-300 rounded-md hover:border-gray-400">
|
bg-[length:80%] bg-center bg-no-repeat
|
||||||
<%= link_to services_storage_path,
|
bg-[url(/img/logos/icon_discourse.svg)]">
|
||||||
|
<%= link_to "#{Setting.discourse_public_url}/session/sso?return_path=/",
|
||||||
class: "block h-full px-6 py-6 rounded-md" do %>
|
class: "block h-full px-6 py-6 rounded-md" do %>
|
||||||
<h3 class="mb-3.5">Storage</h3>
|
<h3 class="mb-3.5">Discourse</h3>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Sync your data between apps and devices
|
Community forums and support/help site
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if Setting.gitea_enabled? %>
|
<% if Setting.gitea_enabled? %>
|
||||||
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
||||||
bg-cover bg-center bg-no-repeat
|
bg-[length:92%] bg-center bg-no-repeat
|
||||||
bg-[url(/img/logos/icon_gitea.png)]">
|
bg-[url(/img/logos/icon_gitea.png)]">
|
||||||
<%= link_to Setting.gitea_public_url,
|
<%= link_to Setting.gitea_public_url,
|
||||||
class: "block h-full px-6 py-6 rounded-md" do %>
|
class: "block h-full px-6 py-6 rounded-md" do %>
|
||||||
@@ -92,7 +96,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<% if Setting.droneci_enabled? %>
|
<% if Setting.droneci_enabled? %>
|
||||||
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
||||||
bg-cover bg-[center_top_-70px] bg-no-repeat
|
bg-[length:86%] bg-[center_top_-60px] bg-no-repeat
|
||||||
bg-[url(/img/logos/icon_droneci.svg)]">
|
bg-[url(/img/logos/icon_droneci.svg)]">
|
||||||
<%= link_to Setting.droneci_public_url,
|
<%= link_to Setting.droneci_public_url,
|
||||||
class: "block h-full px-6 py-6 rounded-md" do %>
|
class: "block h-full px-6 py-6 rounded-md" do %>
|
||||||
|
|||||||
@@ -100,6 +100,14 @@
|
|||||||
["Website", "https://www.thunderbird.net"]
|
["Website", "https://www.thunderbird.net"]
|
||||||
]
|
]
|
||||||
) %>
|
) %>
|
||||||
|
<%= render AppInfoComponent.new(
|
||||||
|
name: "Geary",
|
||||||
|
description: "Built around conversations, for the GNOME desktop",
|
||||||
|
icon_path: "/img/logos/icon_geary.png",
|
||||||
|
links: [
|
||||||
|
["Website", "https://wiki.gnome.org/Apps/Geary"]
|
||||||
|
]
|
||||||
|
) %>
|
||||||
</div>
|
</div>
|
||||||
<div id="apps-windows" class="hidden grid grid-cols-1 gap-6"
|
<div id="apps-windows" class="hidden grid grid-cols-1 gap-6"
|
||||||
data-tabs-target="panel">
|
data-tabs-target="panel">
|
||||||
|
|||||||
@@ -2,15 +2,143 @@
|
|||||||
|
|
||||||
<%= render MainSimpleComponent.new do %>
|
<%= render MainSimpleComponent.new do %>
|
||||||
<section>
|
<section>
|
||||||
<h3 class="mb-10">Connected Apps</h3>
|
<p class="mb-6">
|
||||||
<% if @rs_auths.any? %>
|
Store and synchronize your app data across different devices.
|
||||||
<div class="w-full grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-y-10 gap-x-12">
|
</p>
|
||||||
<% @rs_auths.each do |auth| %>
|
</section>
|
||||||
<%= render RsAuthComponent.new(auth: auth) %>
|
|
||||||
<% end %>
|
<%= render partial: "shared/tabnav_remotestorage" %>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h3>Your Storage Address</h3>
|
||||||
|
<p class="mb-6">
|
||||||
|
In order to connect an app to your storage account, give it your address:
|
||||||
|
</p>
|
||||||
|
<p data-controller="clipboard" class="flex gap-1 sm:w-2/5">
|
||||||
|
<input type="text" id="user_address" class="grow"
|
||||||
|
value=<%= current_user.address %> disabled="disabled"
|
||||||
|
data-clipboard-target="source" />
|
||||||
|
<button id="copy-user-address" class="btn-md btn-icon btn-outline shrink-0"
|
||||||
|
data-clipboard-target="trigger" data-action="clipboard#copy"
|
||||||
|
title="Copy to clipboard">
|
||||||
|
<span class="content-initial">
|
||||||
|
<%= render partial: "icons/copy", locals: { custom_class: "text-blue-600 h-4 w-4 inline" } %>
|
||||||
|
</span>
|
||||||
|
<span class="content-active hidden">
|
||||||
|
<%= render partial: "icons/check", locals: { custom_class: "text-blue-600 h-4 w-4 inline" } %>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h3>Recommended Apps</h3>
|
||||||
|
<div data-controller="tabs"
|
||||||
|
data-tabs-active-tab-class="-mb-px border-gray-200 border-l border-t border-r rounded-t text-indigo-600 hover:text-indigo-600"
|
||||||
|
data-tabs-inactive-tab-class="text-gray-500 hover:text-gray-700"
|
||||||
|
class="mb-12">
|
||||||
|
<select data-action="tabs#change" data-tabs-target="select"
|
||||||
|
class="block w-full mb-8 sm:hidden">
|
||||||
|
<option>Productivity</option>
|
||||||
|
<option>Bookmarks</option>
|
||||||
|
<option>Reading</option>
|
||||||
|
<option>File sharing</option>
|
||||||
|
<option>Learning</option>
|
||||||
|
</select>
|
||||||
|
<ul class="hidden sm:flex list-reset mb-8 border-gray-200 border-b">
|
||||||
|
<li class="mr-2" data-tabs-target="tab" data-action="click->tabs#change:prevent">
|
||||||
|
<a href="#" class="bg-white inline-block py-2 px-4 font-semibold no-underline">
|
||||||
|
Productivity
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mr-2" data-tabs-target="tab" data-action="click->tabs#change:prevent">
|
||||||
|
<a href="#" class="bg-white inline-block py-2 px-4 font-semibold no-underline">
|
||||||
|
Bookmarks
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mr-2" data-tabs-target="tab" data-action="click->tabs#change:prevent">
|
||||||
|
<a href="#" class="bg-white inline-block py-2 px-4 font-semibold no-underline">
|
||||||
|
Reading
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mr-2" data-tabs-target="tab" data-action="click->tabs#change:prevent">
|
||||||
|
<a href="#" class="bg-white inline-block py-2 px-4 font-semibold no-underline">
|
||||||
|
File sharing
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mr-2" data-tabs-target="tab" data-action="click->tabs#change:prevent">
|
||||||
|
<a href="#" class="bg-white inline-block py-2 px-4 font-semibold no-underline">
|
||||||
|
Learning
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="hidden grid grid-cols-1 gap-6" data-tabs-target="panel">
|
||||||
|
<%= render AppInfoComponent.new(
|
||||||
|
name: "Hyperdraft",
|
||||||
|
description: "Create text notes and (optionally) turn them into a website",
|
||||||
|
icon_path: "/img/app_icons/hyperdraft.png",
|
||||||
|
links: [
|
||||||
|
["Website", "https://hyperdraft.rosano.ca"],
|
||||||
|
]
|
||||||
|
) %>
|
||||||
|
<%= render AppInfoComponent.new(
|
||||||
|
name: "Notes Together",
|
||||||
|
description: "A powerful note-taking app, with support for attaching images and other files",
|
||||||
|
icon_path: "/img/app_icons/notes-together.png",
|
||||||
|
links: [
|
||||||
|
["Web App", "https://notestogether.hominidsoftware.com"],
|
||||||
|
]
|
||||||
|
) %>
|
||||||
|
<%= render AppInfoComponent.new(
|
||||||
|
name: "Papiers",
|
||||||
|
description: "A simple note-taking app",
|
||||||
|
icon_path: "/img/app_icons/papiers.png",
|
||||||
|
links: [
|
||||||
|
["Web App", "https://papiers.gitlab.io"],
|
||||||
|
]
|
||||||
|
) %>
|
||||||
|
</div>
|
||||||
|
<div class="hidden grid grid-cols-1 gap-6" data-tabs-target="panel">
|
||||||
|
<%= render AppInfoComponent.new(
|
||||||
|
name: "Webmarks",
|
||||||
|
description: "Archive your bookmarks in your remote storage",
|
||||||
|
icon_path: "/img/app_icons/webmarks.png",
|
||||||
|
links: [
|
||||||
|
["Web App", "https://webmarks.5apps.com"],
|
||||||
|
]
|
||||||
|
) %>
|
||||||
|
</div>
|
||||||
|
<div class="hidden grid grid-cols-1 gap-6" data-tabs-target="panel">
|
||||||
|
<%= render AppInfoComponent.new(
|
||||||
|
name: "Pétrolette",
|
||||||
|
description: "A news aggregator that syncs with your remote storage",
|
||||||
|
icon_path: "/img/app_icons/petrolette.png",
|
||||||
|
links: [
|
||||||
|
["Web App", "https://petrolette.space"],
|
||||||
|
]
|
||||||
|
) %>
|
||||||
|
</div>
|
||||||
|
<div class="hidden grid grid-cols-1 gap-6" data-tabs-target="panel">
|
||||||
|
<%= render AppInfoComponent.new(
|
||||||
|
name: "Sharesome",
|
||||||
|
description: "Quickly and easily share files from your remote storage",
|
||||||
|
icon_path: "/img/app_icons/sharesome.png",
|
||||||
|
links: [
|
||||||
|
["Web App", "https://sharesome.5apps.com"],
|
||||||
|
]
|
||||||
|
) %>
|
||||||
|
</div>
|
||||||
|
<div class="hidden grid grid-cols-1 gap-6" data-tabs-target="panel">
|
||||||
|
<%= render AppInfoComponent.new(
|
||||||
|
name: "Kommit",
|
||||||
|
description: "Create flashcards and learn them with spaced-repetition",
|
||||||
|
icon_path: "/img/app_icons/kommit.png",
|
||||||
|
links: [
|
||||||
|
["Website", "https://kommit.rosano.ca"],
|
||||||
|
]
|
||||||
|
) %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% else %>
|
|
||||||
<p>No apps connected yet.</p>
|
|
||||||
<% end %>
|
|
||||||
</section>
|
</section>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
33
app/views/services/rs_auths/index.html.erb
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<%= render HeaderComponent.new(title: "Storage") %>
|
||||||
|
|
||||||
|
<%= render MainSimpleComponent.new do %>
|
||||||
|
<section>
|
||||||
|
<p class="mb-6">
|
||||||
|
Store and synchronize your app data across different devices.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<%= render partial: "shared/tabnav_remotestorage" %>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<% if @rs_auths.any? %>
|
||||||
|
<div class="w-full grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-y-10 gap-x-12 mt-4">
|
||||||
|
<% @rs_auths.each do |auth| %>
|
||||||
|
<%= render RsAuthComponent.new(auth: auth) %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="mt-4 mb-12 inline-flex align-center items-center">
|
||||||
|
<%= image_tag("/img/illustrations/undraw_friends_r511.svg", class: 'h-48') %>
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
No apps connected
|
||||||
|
</h3>
|
||||||
|
<p class="text-gray-500">
|
||||||
|
When connected, your apps will show up here.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</section>
|
||||||
|
<% end %>
|
||||||
14
app/views/shared/_tabnav_remotestorage.html.erb
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<section>
|
||||||
|
<div class="border-b border-gray-200">
|
||||||
|
<nav class="-mb-px flex" aria-label="Tabs">
|
||||||
|
<%= render TabnavLinkComponent.new(
|
||||||
|
name: "Info", path: services_storage_path,
|
||||||
|
active: current_page?(services_storage_path)
|
||||||
|
) %>
|
||||||
|
<%= render TabnavLinkComponent.new(
|
||||||
|
name: "Connected Apps", path: apps_services_storage_path,
|
||||||
|
active: current_page?(apps_services_storage_path)
|
||||||
|
) %>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@@ -48,7 +48,8 @@ Rails.application.routes.draw do
|
|||||||
end
|
end
|
||||||
|
|
||||||
resource :storage, controller: 'remotestorage', only: [:show] do
|
resource :storage, controller: 'remotestorage', only: [:show] do
|
||||||
resources :rs_auths, only: [:destroy] do
|
get :apps, to: "rs_auths#index"
|
||||||
|
resources :rs_auths, only: [:index, :destroy] do
|
||||||
member do
|
member do
|
||||||
get :revoke, to: 'rs_auths#destroy'
|
get :revoke, to: 'rs_auths#destroy'
|
||||||
get :launch_app
|
get :launch_app
|
||||||
|
|||||||
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
|
||||||
@@ -47,6 +47,9 @@ services:
|
|||||||
RS_REDIS_URL: redis://redis:6379/1
|
RS_REDIS_URL: redis://redis:6379/1
|
||||||
RS_STORAGE_URL: "http://localhost:4567"
|
RS_STORAGE_URL: "http://localhost:4567"
|
||||||
S3_ENABLED: false
|
S3_ENABLED: false
|
||||||
|
NOSTR_PUBLIC_KEY: bdd76ce2934b2f591f9fad2ebe9da18f20d2921de527494ba00eeaa0a0efadcf
|
||||||
|
NOSTR_PRIVATE_KEY: 7c3ef7e448505f0615137af38569d01807d3b05b5005d5ecf8aaafcd40323cea
|
||||||
|
NOSTR_RELAY_URL: "ws://strfry:7777"
|
||||||
depends_on:
|
depends_on:
|
||||||
- ldap
|
- ldap
|
||||||
- redis
|
- redis
|
||||||
@@ -111,9 +114,7 @@ services:
|
|||||||
image: gitea.kosmos.org/kosmos/strfry-deno:1.1.1
|
image: gitea.kosmos.org/kosmos/strfry-deno:1.1.1
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker/strfry/strfry.conf:/etc/strfry.conf
|
- ./docker/strfry/strfry.conf:/etc/strfry.conf
|
||||||
- ./extras/strfry/ldap-policy.ts:/opt/ldap-policy.ts
|
- ./extras/strfry:/opt/strfry
|
||||||
- ./extras/strfry/strfry-policy.ts:/opt/strfry-policy.ts
|
|
||||||
- ./extras/strfry/strfry-sync.ts:/opt/strfry-sync.ts
|
|
||||||
- strfry-data:/var/lib/strfry
|
- strfry-data:/var/lib/strfry
|
||||||
networks:
|
networks:
|
||||||
- external_network
|
- external_network
|
||||||
@@ -125,6 +126,7 @@ services:
|
|||||||
LDAP_BIND_DN: 'cn=Directory Manager'
|
LDAP_BIND_DN: 'cn=Directory Manager'
|
||||||
LDAP_PASSWORD: passthebutter
|
LDAP_PASSWORD: passthebutter
|
||||||
LDAP_SEARCH_DN: 'ou=kosmos.org,cn=users,dc=kosmos,dc=org'
|
LDAP_SEARCH_DN: 'ou=kosmos.org,cn=users,dc=kosmos,dc=org'
|
||||||
|
WHITELIST_PUBKEYS: 'bdd76ce2934b2f591f9fad2ebe9da18f20d2921de527494ba00eeaa0a0efadcf'
|
||||||
|
|
||||||
# phpldapadmin:
|
# phpldapadmin:
|
||||||
# image: osixia/phpldapadmin:0.9.0
|
# image: osixia/phpldapadmin:0.9.0
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ relay {
|
|||||||
|
|
||||||
writePolicy {
|
writePolicy {
|
||||||
# If non-empty, path to an executable script that implements the writePolicy plugin logic
|
# If non-empty, path to an executable script that implements the writePolicy plugin logic
|
||||||
plugin = "/opt/strfry-policy.ts"
|
plugin = "/opt/strfry/strfry-policy.ts"
|
||||||
}
|
}
|
||||||
|
|
||||||
compression {
|
compression {
|
||||||
|
|||||||
5
extras/strfry/deno.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"@nostr/tools": "jsr:@nostr/tools@^2.3.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
196
extras/strfry/deno.lock
generated
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
{
|
||||||
|
"version": "3",
|
||||||
|
"packages": {
|
||||||
|
"specifiers": {
|
||||||
|
"jsr:@nostr/tools@^2.3.1": "jsr:@nostr/tools@2.3.1",
|
||||||
|
"npm:@noble/ciphers@^0.5.1": "npm:@noble/ciphers@0.5.3",
|
||||||
|
"npm:@noble/curves@1.2.0": "npm:@noble/curves@1.2.0",
|
||||||
|
"npm:@noble/hashes@1.3.1": "npm:@noble/hashes@1.3.1",
|
||||||
|
"npm:@scure/base@1.1.1": "npm:@scure/base@1.1.1",
|
||||||
|
"npm:ldapts": "npm:ldapts@7.0.12"
|
||||||
|
},
|
||||||
|
"jsr": {
|
||||||
|
"@nostr/tools@2.3.1": {
|
||||||
|
"integrity": "af01dc45cb28784c584d7a0699707196f397bcc53946efa582a01b11ddde4d61",
|
||||||
|
"dependencies": [
|
||||||
|
"npm:@noble/ciphers@^0.5.1",
|
||||||
|
"npm:@noble/curves@1.2.0",
|
||||||
|
"npm:@noble/hashes@1.3.1",
|
||||||
|
"npm:@scure/base@1.1.1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"npm": {
|
||||||
|
"@noble/ciphers@0.5.3": {
|
||||||
|
"integrity": "sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==",
|
||||||
|
"dependencies": {}
|
||||||
|
},
|
||||||
|
"@noble/curves@1.2.0": {
|
||||||
|
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@noble/hashes": "@noble/hashes@1.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@noble/hashes@1.3.1": {
|
||||||
|
"integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==",
|
||||||
|
"dependencies": {}
|
||||||
|
},
|
||||||
|
"@noble/hashes@1.3.2": {
|
||||||
|
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
|
||||||
|
"dependencies": {}
|
||||||
|
},
|
||||||
|
"@scure/base@1.1.1": {
|
||||||
|
"integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==",
|
||||||
|
"dependencies": {}
|
||||||
|
},
|
||||||
|
"@types/asn1@0.2.4": {
|
||||||
|
"integrity": "sha512-V91DSJ2l0h0gRhVP4oBfBzRBN9lAbPUkGDMCnwedqPKX2d84aAMc9CulOvxdw1f7DfEYx99afab+Rsm3e52jhA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "@types/node@18.16.19"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/node@18.16.19": {
|
||||||
|
"integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==",
|
||||||
|
"dependencies": {}
|
||||||
|
},
|
||||||
|
"@types/uuid@9.0.8": {
|
||||||
|
"integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
|
||||||
|
"dependencies": {}
|
||||||
|
},
|
||||||
|
"asn1@0.2.6": {
|
||||||
|
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"safer-buffer": "safer-buffer@2.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"debug@4.3.5": {
|
||||||
|
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "ms@2.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ldapts@7.0.12": {
|
||||||
|
"integrity": "sha512-orwgIejUi/ZyGah9y8jWZmFUg8Ci5M8WAv0oZjSf3MVuk1sRBdor9Qy1ttGHbYpWj96HXKFunQ8AYZ8WWGp17g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/asn1": "@types/asn1@0.2.4",
|
||||||
|
"@types/uuid": "@types/uuid@9.0.8",
|
||||||
|
"asn1": "asn1@0.2.6",
|
||||||
|
"debug": "debug@4.3.5",
|
||||||
|
"strict-event-emitter-types": "strict-event-emitter-types@2.0.0",
|
||||||
|
"uuid": "uuid@9.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms@2.1.2": {
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||||
|
"dependencies": {}
|
||||||
|
},
|
||||||
|
"safer-buffer@2.1.2": {
|
||||||
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||||
|
"dependencies": {}
|
||||||
|
},
|
||||||
|
"strict-event-emitter-types@2.0.0": {
|
||||||
|
"integrity": "sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==",
|
||||||
|
"dependencies": {}
|
||||||
|
},
|
||||||
|
"uuid@9.0.1": {
|
||||||
|
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||||
|
"dependencies": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"remote": {
|
||||||
|
"https://deno.land/std@0.181.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462",
|
||||||
|
"https://deno.land/std@0.181.0/bytes/bytes_list.ts": "b4cbdfd2c263a13e8a904b12d082f6177ea97d9297274a4be134e989450dfa6a",
|
||||||
|
"https://deno.land/std@0.181.0/bytes/concat.ts": "d26d6f3d7922e6d663dacfcd357563b7bf4a380ce5b9c2bbe0c8586662f25ce2",
|
||||||
|
"https://deno.land/std@0.181.0/bytes/copy.ts": "939d89e302a9761dcf1d9c937c7711174ed74c59eef40a1e4569a05c9de88219",
|
||||||
|
"https://deno.land/std@0.181.0/fmt/colors.ts": "d67e3cd9f472535241a8e410d33423980bec45047e343577554d3356e1f0ef4e",
|
||||||
|
"https://deno.land/std@0.181.0/io/buf_reader.ts": "abeb92b18426f11d72b112518293a96aef2e6e55f80b84235e8971ac910affb5",
|
||||||
|
"https://deno.land/std@0.181.0/io/buf_writer.ts": "48c33c8f00b61dcbc7958706741cec8e59810bd307bc6a326cbd474fe8346dfd",
|
||||||
|
"https://deno.land/std@0.181.0/io/buffer.ts": "17f4410eaaa60a8a85733e8891349a619eadfbbe42e2f319283ce2b8f29723ab",
|
||||||
|
"https://deno.land/std@0.181.0/io/copy_n.ts": "0cc7ce07c75130f6fc18621ec1911c36e147eb9570664fee0ea12b1988167590",
|
||||||
|
"https://deno.land/std@0.181.0/io/limited_reader.ts": "6c9a216f8eef39c1ee2a6b37a29372c8fc63455b2eeb91f06d9646f8f759fc8b",
|
||||||
|
"https://deno.land/std@0.181.0/io/mod.ts": "2665bcccc1fd6e8627cca167c3e92aaecbd9897556b6f69e6d258070ef63fd9b",
|
||||||
|
"https://deno.land/std@0.181.0/io/multi_reader.ts": "9c2a0a31686c44b277e16da1d97b4686a986edcee48409b84be25eedbc39b271",
|
||||||
|
"https://deno.land/std@0.181.0/io/read_delim.ts": "c02b93cc546ae8caad8682ae270863e7ace6daec24c1eddd6faabc95a9d876a3",
|
||||||
|
"https://deno.land/std@0.181.0/io/read_int.ts": "7cb8bcdfaf1107586c3bacc583d11c64c060196cb070bb13ae8c2061404f911f",
|
||||||
|
"https://deno.land/std@0.181.0/io/read_lines.ts": "c526c12a20a9386dc910d500f9cdea43cba974e853397790bd146817a7eef8cc",
|
||||||
|
"https://deno.land/std@0.181.0/io/read_long.ts": "f0aaa420e3da1261c5d33c5e729f09922f3d9fa49f046258d4ff7a00d800c71e",
|
||||||
|
"https://deno.land/std@0.181.0/io/read_range.ts": "28152daf32e43dd9f7d41d8466852b0d18ad766cd5c4334c91fef6e1b3a74eb5",
|
||||||
|
"https://deno.land/std@0.181.0/io/read_short.ts": "805cb329574b850b84bf14a92c052c59b5977a492cd780c41df8ad40826c1a20",
|
||||||
|
"https://deno.land/std@0.181.0/io/read_string_delim.ts": "5dc9f53bdf78e7d4ee1e56b9b60352238ab236a71c3e3b2a713c3d78472a53ce",
|
||||||
|
"https://deno.land/std@0.181.0/io/slice_long_to_bytes.ts": "48d9bace92684e880e46aa4a2520fc3867f9d7ce212055f76ecc11b22f9644b7",
|
||||||
|
"https://deno.land/std@0.181.0/io/string_reader.ts": "da0f68251b3d5b5112485dfd4d1b1936135c9b4d921182a7edaf47f74c25cc8f",
|
||||||
|
"https://deno.land/std@0.181.0/io/string_writer.ts": "8a03c5858c24965a54c6538bed15f32a7c72f5704a12bda56f83a40e28e5433e",
|
||||||
|
"https://deno.land/std@0.181.0/testing/_diff.ts": "1a3c044aedf77647d6cac86b798c6417603361b66b54c53331b312caeb447aea",
|
||||||
|
"https://deno.land/std@0.181.0/testing/_format.ts": "a69126e8a469009adf4cf2a50af889aca364c349797e63174884a52ff75cf4c7",
|
||||||
|
"https://deno.land/std@0.181.0/testing/asserts.ts": "e16d98b4d73ffc4ed498d717307a12500ae4f2cbe668f1a215632d19fcffc22f",
|
||||||
|
"https://deno.land/std@0.224.0/dotenv/mod.ts": "0180eaeedaaf88647318811cdaa418cc64dc51fb08354f91f5f480d0a1309f7d",
|
||||||
|
"https://deno.land/std@0.224.0/dotenv/parse.ts": "09977ff88dfd1f24f9973a338f0f91bbdb9307eb5ff6085446e7c423e4c7ba0c",
|
||||||
|
"https://deno.land/std@0.224.0/dotenv/stringify.ts": "275da322c409170160440836342eaa7cf012a1d11a7e700d8ca4e7f2f8aa4615",
|
||||||
|
"https://deno.land/std@0.88.0/async/deferred.ts": "f89ed49ba5e1dd0227c6bd5b23f017be46c3f92e4f0338dda08ff5aa54b9f6c9",
|
||||||
|
"https://deno.land/std@0.88.0/async/delay.ts": "9de1d8d07d1927767ab7f82434b883f3d8294fb19cad819691a2ad81a728cf3d",
|
||||||
|
"https://deno.land/std@0.88.0/async/mod.ts": "253b41c658d768613eacfb11caa0a9ca7148442f932018a45576f7f27554c853",
|
||||||
|
"https://deno.land/std@0.88.0/async/mux_async_iterator.ts": "b9091909db04cdb0af6f7807677372f64c1488de6c4bd86004511b064bf230d6",
|
||||||
|
"https://deno.land/std@0.88.0/async/pool.ts": "876f9e6815366cd017a3b4fbb9e9ae40310b1b6972f1bd541c94358bc11fb7e5",
|
||||||
|
"https://deno.land/std@0.88.0/encoding/base64.ts": "eecae390f1f1d1cae6f6c6d732ede5276bf4b9cd29b1d281678c054dc5cc009e",
|
||||||
|
"https://deno.land/std@0.88.0/encoding/hex.ts": "f952e0727bddb3b2fd2e6889d104eacbd62e92091f540ebd6459317a61932d9b",
|
||||||
|
"https://deno.land/std@0.88.0/fmt/colors.ts": "db22b314a2ae9430ae7460ce005e0a7130e23ae1c999157e3bb77cf55800f7e4",
|
||||||
|
"https://deno.land/std@0.88.0/node/_utils.ts": "067c386d676432e9418808851e8de72df7774f009a652904f62358b4c94504cf",
|
||||||
|
"https://deno.land/std@0.88.0/node/buffer.ts": "e98af24a3210d8fc3f022b6eb26d6e5bdf98fb0e02931e5983d20db9fed1b590",
|
||||||
|
"https://deno.land/std@0.88.0/testing/_diff.ts": "961eaf6d9f5b0a8556c9d835bbc6fa74f5addd7d3b02728ba7936ff93364f7a3",
|
||||||
|
"https://deno.land/std@0.88.0/testing/asserts.ts": "7fae8128125106ddf8e4b3ac84cc3b5fb2378e3fbf8ba38947ebe24faa002ce2",
|
||||||
|
"https://deno.land/x/module_cache@0.0.3/mod.ts": "c5e724477146e68b7a4d7ba440cd18f2ef4b28e4244ce48358c79efe98e3cd24",
|
||||||
|
"https://deno.land/x/sqlite@v3.7.1/build/sqlite.js": "c59f109f100c2bae0b9342f04e0d400583e2e3211d08bb71095177a4109ee5bf",
|
||||||
|
"https://deno.land/x/sqlite@v3.7.1/build/vfs.js": "08533cc78fb29b9d9bd62f6bb93e5ef333407013fed185776808f11223ba0e70",
|
||||||
|
"https://deno.land/x/sqlite@v3.7.1/mod.ts": "e09fc79d8065fe222578114b109b1fd60077bff1bb75448532077f784f4d6a83",
|
||||||
|
"https://deno.land/x/sqlite@v3.7.1/src/constants.ts": "90f3be047ec0a89bcb5d6fc30db121685fc82cb00b1c476124ff47a4b0472aa9",
|
||||||
|
"https://deno.land/x/sqlite@v3.7.1/src/db.ts": "59c6c2b5c4127132558bb8c610eadd811822f1a5d7f9c509704179ca192f94e0",
|
||||||
|
"https://deno.land/x/sqlite@v3.7.1/src/error.ts": "f7a15cb00d7c3797da1aefee3cf86d23e0ae92e73f0ba3165496c3816ab9503a",
|
||||||
|
"https://deno.land/x/sqlite@v3.7.1/src/function.ts": "e4c83b8ec64bf88bafad2407376b0c6a3b54e777593c70336fb40d43a79865f2",
|
||||||
|
"https://deno.land/x/sqlite@v3.7.1/src/query.ts": "d58abda928f6582d77bad685ecf551b1be8a15e8e38403e293ec38522e030cad",
|
||||||
|
"https://deno.land/x/sqlite@v3.7.1/src/wasm.ts": "e79d0baa6e42423257fb3c7cc98091c54399254867e0f34a09b5bdef37bd9487",
|
||||||
|
"https://esm.sh/nostr-tools@1.8.4?pin=v115": "62e5b620dbbaea0ee399efcc700260da12836a353fa521d35969d3454e591a77",
|
||||||
|
"https://esm.sh/v115/@noble/hashes@1.2.0/denonext/_assert.js": "2d47b1ae1c443fbcda3aa75e6d66c26da566d1775dcd757165314e8e9d1162da",
|
||||||
|
"https://esm.sh/v115/@noble/hashes@1.2.0/denonext/crypto.js": "0880be2fb91177484b9a5916a286aadce6a1c8b1b5cf6be47393361e6b121a17",
|
||||||
|
"https://esm.sh/v115/@noble/hashes@1.2.0/denonext/hmac.js": "cdb442a8326674449570b98daa44b07317908eae81205c178cab542ea754b91d",
|
||||||
|
"https://esm.sh/v115/@noble/hashes@1.2.0/denonext/pbkdf2.js": "e8b8e2ff70ecb35442fabfece10e76850ac8dc6aaf44a769871c9e6dbe60d264",
|
||||||
|
"https://esm.sh/v115/@noble/hashes@1.2.0/denonext/ripemd160.js": "8cd5e59afc12f6f6a2c980495f699a76d812ca30772d4c085ff8477fe4b1a2fe",
|
||||||
|
"https://esm.sh/v115/@noble/hashes@1.2.0/denonext/sha256.js": "8dec7d1bb4d0799f9cdf8f9ea7d8c3e91790255d547defcf62a626a0a190185e",
|
||||||
|
"https://esm.sh/v115/@noble/hashes@1.2.0/denonext/sha512.js": "85ccf57544faca95a6aeab11951f98f49e56b3cbad0618f624838c7e8fb4361d",
|
||||||
|
"https://esm.sh/v115/@noble/hashes@1.2.0/denonext/utils.js": "11431fc23031cb324977bc992e699fda8ec7c63fcc17c2b4f71a3902d48e99e5",
|
||||||
|
"https://esm.sh/v115/@noble/secp256k1@1.7.0/denonext/secp256k1.mjs": "36fb68b95b2f62de23d275be52b2eec68813083b93b78f7032492188ef59c77b",
|
||||||
|
"https://esm.sh/v115/@noble/secp256k1@1.7.1/denonext/secp256k1.mjs": "43c5a7ba14ae81b36e5ce64abf45962119527e926cddb764b7e510869b05f0bd",
|
||||||
|
"https://esm.sh/v115/@scure/base@1.1.1/denonext/base.mjs": "8f9cb853c4f6a4367c2f5bfb921d54b4ed61e41829944435e5878781b54d94a9",
|
||||||
|
"https://esm.sh/v115/@scure/bip32@1.1.4/denonext/bip32.mjs": "05471356192b1286874be6c28bea4ebac6dd6bc680bce795640604bb317c2165",
|
||||||
|
"https://esm.sh/v115/@scure/bip39@1.1.1/denonext/bip39.mjs": "00ccac2e221996db35b6780b3ae2cf37a153111bd1d348c9defe3a4341ec683d",
|
||||||
|
"https://esm.sh/v115/@scure/bip39@1.1.1/denonext/wordlists/english.js": "72ca7f3b2e856a62caa00441579008da89ea21a9c8a428ae547cdcffd17ae40c",
|
||||||
|
"https://esm.sh/v115/nostr-tools@1.8.4/denonext/nostr-tools.mjs": "f8023312404e4a83f0c052653643bcdbf5169a1585bd5399f11c65f37f7bcf16",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/mod.ts": "26add79f9bf2b12d088bacd3417dbb590684171f80be2dbf2e6b83b324df54f7",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/deps.ts": "3c06f4dafe1b04c2413977e9dfdc4956136505f401e0ced14a1c7aff484ad699",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/io.ts": "1f87789a4ea53ed73438c475bb4b6a82eba2bb389d4c8c9179450a4b490f1953",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/pipeline.ts": "4b881ebc1893b4f9f8dcbab260097a0402e0a398b937ef6723915db7c2a86a90",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/policies/anti-duplication-policy.ts": "82a3868b671e68e1379104c0ee1fb8085a5c2d9b802b6eedf31eaae87e778a53",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/policies/filter-policy.ts": "320e736a01bf82d95ab5bc0b8de97c635d71f7779925ff209e3064b01e145e72",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/policies/hellthread-policy.ts": "965469606bdbb04b4bb0c61f90b7f6f0d073e394fa271e17784d2afde085476e",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/policies/keyword-policy.ts": "c88db7137d336631b4fcc3532c5059c4a1e27caa50d6332a5fb593bf295d28df",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/policies/noop-policy.ts": "e4164ab252c328d3ec72310d458cdcfc85bfbfdb7504f41e1d9ab4fd6fdcf4ef",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/policies/openai-policy.ts": "cde09abe6dbdebdbb77ea13731a27ce8bcacbbd1fb21760d7784878dca587d81",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/policies/pow-policy.ts": "d667623a4570e888d0cfdb41bf99bbbac0eb44eab5d97f5be1eeb190e06d34cb",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/policies/pubkey-ban-policy.ts": "af2e3d6f5266bcb1785325a004a0a92088d18fa2433760f807158314184a82c9",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/policies/rate-limit-policy.ts": "02e8539f30e67f7f7541628120358d70c4b05f362b4f21bbcceda475a6d3e357",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/policies/read-only-policy.ts": "ec849ed7b06133bc11e3ce40412dd58469838376764a4326ffc043ea985c9739",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/policies/regex-policy.ts": "626f7d4eb61eace9aa685a4f51b0b142b30abc96554ac5e375bbf3dc2a5ab685",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/policies/whitelist-policy.ts": "f5cb4f616dc41c88505eb45adb2b2102a284ae7351ce9f76a76d53dd7b8bf575",
|
||||||
|
"https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/src/types.ts": "792aa1196dd290d815081ef874f8e66dacde344c9e30a8bf9031a1ebeb1da21d",
|
||||||
|
"https://raw.githubusercontent.com/alexgleason/Keydb/1bda308df9e589339532daf31f1717ef7a59d2af/adapter.ts": "32e5182648011b188952ada0528f564b374260449ec3b06237f36225d4d19510",
|
||||||
|
"https://raw.githubusercontent.com/alexgleason/Keydb/1bda308df9e589339532daf31f1717ef7a59d2af/jsonb.ts": "1b540f8bd0b43fe847cd3e2a852d2f53e610cd77b81c11d175ebe91a3f110be8",
|
||||||
|
"https://raw.githubusercontent.com/alexgleason/Keydb/1bda308df9e589339532daf31f1717ef7a59d2af/keydb.ts": "616c4c866c9e11c29d5654d367468ed51b689565043f53fdeb5eb66f25138156",
|
||||||
|
"https://raw.githubusercontent.com/alexgleason/Keydb/1bda308df9e589339532daf31f1717ef7a59d2af/memory.ts": "f0ab6faf293c4ad3539fd3cf89c764d7f34d39d24e471ea59eebb5d1f5a510dc",
|
||||||
|
"https://raw.githubusercontent.com/alexgleason/Keydb/1bda308df9e589339532daf31f1717ef7a59d2af/sqlite.ts": "c8f172cfea9425cb16e844622375c9578db508de7d710ad3987cf6cd6bff197a"
|
||||||
|
},
|
||||||
|
"workspace": {
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@nostr/tools@^2.3.1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,54 @@
|
|||||||
import type { Policy } from 'https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/mod.ts';
|
import type { IterablePubkeys, Policy } from 'https://gitlab.com/soapbox-pub/strfry-policies/-/raw/develop/mod.ts';
|
||||||
import { Client } from 'npm:ldapts';
|
import { Client } from 'npm:ldapts';
|
||||||
|
import { nip57 } from '@nostr/tools';
|
||||||
|
|
||||||
interface LdapConfig {
|
interface LdapConfig {
|
||||||
url: string;
|
url: string;
|
||||||
bindDN: string;
|
bindDN: string;
|
||||||
password: string;
|
password: string;
|
||||||
searchDN: string;
|
searchDN: string;
|
||||||
|
whitelistPubkeys?: IterablePubkeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ldapPolicy: Policy<LdapConfig> = async (msg, opts) => {
|
const ldapPolicy: Policy<LdapConfig> = async (msg, opts) => {
|
||||||
const client = new Client({ url: opts.url });
|
const client = new Client({ url: opts.url });
|
||||||
const { pubkey, kind, tags } = msg.event;
|
const { kind, tags } = msg.event;
|
||||||
|
let { pubkey } = msg.event;
|
||||||
let out = { id: msg.event.id }
|
let out = { id: msg.event.id }
|
||||||
|
|
||||||
|
if (opts.whitelistPubkeys.includes(pubkey)) {
|
||||||
|
out['action'] = 'accept';
|
||||||
|
out['msg'] = '';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zap receipt
|
||||||
|
if (kind === 9735) {
|
||||||
|
const descriptionTag = tags.find(([t, v]) => t === 'description' && v);
|
||||||
|
const invalidZapRequestMsg = 'Zap receipts must contain a valid zap request from a relay member';
|
||||||
|
|
||||||
|
if (typeof descriptionTag === 'undefined') {
|
||||||
|
out['action'] = 'reject';
|
||||||
|
out['msg'] = invalidZapRequestMsg;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
const zapRequestJSON = descriptionTag[1];
|
||||||
|
const validationResult = nip57.validateZapRequest(zapRequestJSON);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// The zap receipt event's pubkey MUST be the same as the recipient's lnurl provider's nostrPubkey (retrieved in step 1 of the protocol flow).
|
||||||
|
// The invoiceAmount contained in the bolt11 tag of the zap receipt MUST equal the amount tag of the zap request (if present).
|
||||||
|
|
||||||
|
if (validationResult === null) {
|
||||||
|
pubkey = JSON.parse(zapRequestJSON).pubkey;
|
||||||
|
} else {
|
||||||
|
out['action'] = 'reject';
|
||||||
|
out['msg'] = invalidZapRequestMsg;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await client.bind(opts.bindDN, opts.password);
|
await client.bind(opts.bindDN, opts.password);
|
||||||
|
|
||||||
@@ -20,14 +56,9 @@ const ldapPolicy: Policy<LdapConfig> = async (msg, opts) => {
|
|||||||
filter: `(nostrKey=${pubkey})`,
|
filter: `(nostrKey=${pubkey})`,
|
||||||
attributes: ['nostrKey']
|
attributes: ['nostrKey']
|
||||||
});
|
});
|
||||||
|
|
||||||
const memberKey = searchEntries[0]?.nostrKey;
|
const memberKey = searchEntries[0]?.nostrKey;
|
||||||
|
|
||||||
const accepted = (memberKey === pubkey);
|
if (memberKey === pubkey) {
|
||||||
// TODO if kind is 9735, check that "description" tag contains valid 9734 event,
|
|
||||||
// signed by memberKey and with "p" tag being the same as pubkey (receipt sender)
|
|
||||||
|
|
||||||
if (accepted) {
|
|
||||||
out['action'] = 'accept';
|
out['action'] = 'accept';
|
||||||
out['msg'] = '';
|
out['msg'] = '';
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ const ldapConfig = {
|
|||||||
bindDN: Deno.env.get("LDAP_BIND_DN"),
|
bindDN: Deno.env.get("LDAP_BIND_DN"),
|
||||||
password: Deno.env.get("LDAP_PASSWORD"),
|
password: Deno.env.get("LDAP_PASSWORD"),
|
||||||
searchDN: Deno.env.get("LDAP_SEARCH_DN"),
|
searchDN: Deno.env.get("LDAP_SEARCH_DN"),
|
||||||
|
whitelistPubkeys: Deno.env.get("WHITELIST_PUBKEYS")?.split(',')
|
||||||
}
|
}
|
||||||
|
|
||||||
for await (const msg of readStdin()) {
|
for await (const msg of readStdin()) {
|
||||||
|
|||||||
BIN
public/img/app_icons/hyperdraft.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
public/img/app_icons/kommit.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
public/img/app_icons/notes-together.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
public/img/app_icons/papiers.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
public/img/app_icons/petrolette.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
public/img/app_icons/sharesome.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
public/img/app_icons/webmarks.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
1
public/img/illustrations/undraw_friends_r511.svg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
public/img/logos/icon_geary.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
11
public/img/logos/icon_mail.svg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg version="1.1" viewBox="-5 -10 110 135" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m63.57 53.199-5.5742 5.5742c-2.1211 2.1211-4.9961 3.3125-7.9961 3.3125s-5.875-1.1914-8-3.3125l-5.5742-5.5742-30.066 30.066c0.90625 0.43359 1.9023 0.66406 2.9258 0.66406h81.43c1.0234 0 2.0195-0.23047 2.9258-0.66406z"
|
||||||
|
style="fill:#4f97ef;fill-opacity:1" />
|
||||||
|
<path d="m96.836 19.934c0.43359 0.90234 0.66406 1.9023 0.66406 2.9219v54.285c0 1.0234-0.23047 2.0195-0.66406 2.9258l-30.066-30.066z"
|
||||||
|
style="fill:#4f97ef;fill-opacity:1" />
|
||||||
|
<path d="m3.1641 19.934 30.066 30.066-30.066 30.066c-0.43359-0.90625-0.66406-1.9023-0.66406-2.9258v-54.285c0-1.0195 0.23047-2.0195 0.66406-2.9219z"
|
||||||
|
style="fill:#4f97ef;fill-opacity:1" />
|
||||||
|
<path d="m93.641 16.734c-0.90625-0.43359-1.9023-0.66406-2.9258-0.66406h-81.43c-1.0234 0-2.0195 0.23047-2.9258 0.66406l38.84 38.84c1.2734 1.2734 3 1.9883 4.8008 1.9883s3.5273-0.71484 4.7969-1.9883z"
|
||||||
|
style="fill:#4f97ef;fill-opacity:1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1018 B |
18
public/img/logos/icon_remotestorage.svg
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Creator: CorelDRAW X7 -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="0.739008in" height="0.853339in" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
|
||||||
|
viewBox="0 0 739 853"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<defs>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
.fil0 {fill:#FF4B03}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g id="Layer_x0020_1">
|
||||||
|
<metadata id="CorelCorpID_0Corel-Layer"/>
|
||||||
|
<polygon class="fil0" points="370,754 0,542 0,640 185,747 370,853 554,747 739,640 739,525 739,525 739,476 739,427 739,378 653,427 370,589 86,427 86,427 86,361 185,418 370,524 554,418 653,361 739,311 739,213 739,213 554,107 370,0 185,107 58,180 144,230 228,181 370,100 511,181 652,263 370,425 87,263 87,263 0,213 0,213 0,311 0,378 0,427 0,476 86,525 185,582 370,689 554,582 653,525 653,590 653,592 "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -2,21 +2,21 @@ require 'rails_helper'
|
|||||||
|
|
||||||
RSpec.describe "Well-known URLs", type: :request do
|
RSpec.describe "Well-known URLs", type: :request do
|
||||||
describe "GET /nostr" do
|
describe "GET /nostr" do
|
||||||
context "without username param" do
|
describe "without username param" do
|
||||||
it "returns a 422 status" do
|
it "returns a 422 status" do
|
||||||
get "/.well-known/nostr.json"
|
get "/.well-known/nostr.json"
|
||||||
expect(response).to have_http_status(:unprocessable_entity)
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "non-existent user" do
|
describe "non-existent user" do
|
||||||
it "returns a 404 status" do
|
it "returns a 404 status" do
|
||||||
get "/.well-known/nostr.json?name=bob"
|
get "/.well-known/nostr.json?name=bob"
|
||||||
expect(response).to have_http_status(:not_found)
|
expect(response).to have_http_status(:not_found)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "user does not have a nostr pubkey configured" do
|
describe "user does not have a nostr pubkey configured" do
|
||||||
let(:user) { create :user, cn: 'spongebob', ou: 'kosmos.org' }
|
let(:user) { create :user, cn: 'spongebob', ou: 'kosmos.org' }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@@ -30,7 +30,7 @@ RSpec.describe "Well-known URLs", type: :request do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "user with nostr pubkey" do
|
describe "user with nostr pubkey" do
|
||||||
let(:user) { create :user, cn: 'bobdylan', ou: 'kosmos.org' }
|
let(:user) { create :user, cn: 'bobdylan', ou: 'kosmos.org' }
|
||||||
before do
|
before do
|
||||||
user.save!
|
user.save!
|
||||||
@@ -45,6 +45,63 @@ RSpec.describe "Well-known URLs", type: :request do
|
|||||||
expect(res["names"].keys.size).to eq(1)
|
expect(res["names"].keys.size).to eq(1)
|
||||||
expect(res["names"]["bobdylan"]).to eq(user.nostr_pubkey)
|
expect(res["names"]["bobdylan"]).to eq(user.nostr_pubkey)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "without relay configured" do
|
||||||
|
before do
|
||||||
|
Setting.nostr_relay_url = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not include a recommended relay" do
|
||||||
|
get "/.well-known/nostr.json?name=bobdylan"
|
||||||
|
res = JSON.parse(response.body)
|
||||||
|
expect(res["relays"]).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with relay configured" do
|
||||||
|
before do
|
||||||
|
Setting.nostr_relay_url = "wss://nostr.kosmos.org"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "includes a recommended relay" do
|
||||||
|
get "/.well-known/nostr.json?name=bobdylan"
|
||||||
|
res = JSON.parse(response.body)
|
||||||
|
expect(res["relays"][user.nostr_pubkey].length).to eq(1)
|
||||||
|
expect(res["relays"][user.nostr_pubkey].first).to eq("wss://nostr.kosmos.org")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "placeholder username for domain's own pubkey" do
|
||||||
|
it "returns the configured nostr pubkey" do
|
||||||
|
get "/.well-known/nostr.json?name=_"
|
||||||
|
res = JSON.parse(response.body)
|
||||||
|
expect(res["names"]["_"]).to eq(Setting.nostr_public_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with relay configured" do
|
||||||
|
before do
|
||||||
|
Setting.nostr_relay_url = "wss://nostr.kosmos.org"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the pubkey and relay" do
|
||||||
|
get "/.well-known/nostr.json?name=_"
|
||||||
|
res = JSON.parse(response.body)
|
||||||
|
expect(res["relays"]["_"].length).to eq(1)
|
||||||
|
expect(res["relays"]["_"].first).to eq("wss://nostr.kosmos.org")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "nostr service integration not enabled" do
|
||||||
|
before do
|
||||||
|
Setting.nostr_enabled = false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a 404 status" do
|
||||||
|
get "/.well-known/nostr.json?name=_"
|
||||||
|
expect(response).to have_http_status(:not_found)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ RSpec.describe NostrManager::PublishZapReceipt, type: :model do
|
|||||||
let(:user) { create :user, ln_account: "123456abcdef" }
|
let(:user) { create :user, ln_account: "123456abcdef" }
|
||||||
let(:zap) { create :zap, user: user }
|
let(:zap) { create :zap, user: user }
|
||||||
|
|
||||||
|
before do
|
||||||
|
Setting.nostr_relay_url = ""
|
||||||
|
end
|
||||||
|
|
||||||
describe "Default/delayed execution" do
|
describe "Default/delayed execution" do
|
||||||
it "publishes zap receipts to all requested relays" do
|
it "publishes zap receipts to all requested relays" do
|
||||||
expect(NostrPublishEventJob).to receive(:perform_later)
|
expect(NostrPublishEventJob).to receive(:perform_later)
|
||||||
@@ -35,6 +39,19 @@ RSpec.describe NostrManager::PublishZapReceipt, type: :model do
|
|||||||
|
|
||||||
described_class.call(zap: zap)
|
described_class.call(zap: zap)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "with own relay configured" do
|
||||||
|
before do
|
||||||
|
Setting.nostr_relay_url = "wss://foobar.kosmos.org"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "also publishes the receipt to our own relay" do
|
||||||
|
expect(NostrPublishEventJob).to receive(:perform_later)
|
||||||
|
.exactly(13).times.and_return(true)
|
||||||
|
|
||||||
|
described_class.call(zap: zap)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||