packages/misskey-forwarder: init

This commit is contained in:
2025-12-24 14:01:35 +08:00
parent 222b0829c8
commit c36e0c52d6
11 changed files with 163 additions and 2 deletions

View File

@@ -61,6 +61,7 @@ inputs:
beesd."/" = {}; beesd."/" = {};
coredns.interface = "ens18"; coredns.interface = "ens18";
headscale = {}; headscale = {};
misskey-forwarder = {};
}; };
}; };
networking.nftables.tables.forward = networking.nftables.tables.forward =

View File

@@ -5,6 +5,10 @@ coturn:
tinc: ENC[AES256_GCM,data:E3OrPA67R48x5FJUW0ZbERlclz8Z/XokAaGTeBQLPEHSeqEArHYSZkdJRZejFrBruJPlGZMPNBQzlIBXOfXKwMnlBDaGJIIJHIzPDGG9W7QF4IIRK/BjVZHFwfKvZtbUDGsqLcCSe5+ttmyucBaFGquXhnD/Tu09uyWtRvS10KAJLY0Z2/16CFB1+8egJIcYw2TFXObo+KR92Va0qwiDSepKaJtYLimDGRKk04QGj+BYa5y8PjIG6bz8UG82mmCiV7XM3EPlSMA=,iv:kawsklNGFbRhxKuUwvNL2WyBxuYu2T/uks1cJ4i8NhA=,tag:V+jAaxQX7JCiR5+wIVW4Nw==,type:str] tinc: ENC[AES256_GCM,data:E3OrPA67R48x5FJUW0ZbERlclz8Z/XokAaGTeBQLPEHSeqEArHYSZkdJRZejFrBruJPlGZMPNBQzlIBXOfXKwMnlBDaGJIIJHIzPDGG9W7QF4IIRK/BjVZHFwfKvZtbUDGsqLcCSe5+ttmyucBaFGquXhnD/Tu09uyWtRvS10KAJLY0Z2/16CFB1+8egJIcYw2TFXObo+KR92Va0qwiDSepKaJtYLimDGRKk04QGj+BYa5y8PjIG6bz8UG82mmCiV7XM3EPlSMA=,iv:kawsklNGFbRhxKuUwvNL2WyBxuYu2T/uks1cJ4i8NhA=,tag:V+jAaxQX7JCiR5+wIVW4Nw==,type:str]
postgresql: postgresql:
headscale: ENC[AES256_GCM,data:z2cyyT1TcIhNJCBeGn072aFI2nAioWZQvpyzoky4tWtMymKlw4ilOtSYAsp+kaNOoqvWSmoAQNJLNzeDk1iTCQ==,iv:hZdS/CAVBO0k/AmX3qw3YwTYgK49Aeu5QI3YCAduiZ0=,tag:2l4GPV/T2GHjAAUDX3LaEA==,type:str] headscale: ENC[AES256_GCM,data:z2cyyT1TcIhNJCBeGn072aFI2nAioWZQvpyzoky4tWtMymKlw4ilOtSYAsp+kaNOoqvWSmoAQNJLNzeDk1iTCQ==,iv:hZdS/CAVBO0k/AmX3qw3YwTYgK49Aeu5QI3YCAduiZ0=,tag:2l4GPV/T2GHjAAUDX3LaEA==,type:str]
misskey-forwarder:
secret: ENC[AES256_GCM,data:MknbcYWGDptZ2PynMFyScA9Ka/KrtBPmMTgy/cSfXIw=,iv:fg2x6fjM/KhnC014UkNAYlHKWgMnamd+0bkjIELs04Y=,tag:H8azwIcxm9DMYQMWlWJQZw==,type:str]
telegramBotToken: ENC[AES256_GCM,data:Ba/De5aBmMSCE6Rucqy8uw7XyPSXgy+1c8tb1uJn27//+U0RrzEQnS6TcRy5rQ==,iv:pWIP626x5om98JxR49iHYUCf50IpJ1MKdi0Mml6+gQU=,tag:rpkQFqd7j+3lfAIzuRybMg==,type:str]
telegramChatId: ENC[AES256_GCM,data:HpwzLKbl1WykNj0uB0I=,iv:zA45v4ZNroZNCdoFntTeonwq+ulHpPey25WiuXGCGi4=,tag:yL6P2Vgv/LxTpDWSnZwTLg==,type:str]
sops: sops:
age: age:
- recipient: age19ax6vm3pv8rph5tq3mmehd9sy9jk823tw8svsd790r0lkslycquqvlwz9m - recipient: age19ax6vm3pv8rph5tq3mmehd9sy9jk823tw8svsd790r0lkslycquqvlwz9m
@@ -25,7 +29,7 @@ sops:
ZXFTU3ZCaW1pTVh0RUJzdDdGdHlPYTgK2mlgcX2kEc8+2UDdBnhUm6IIuh8V6agW ZXFTU3ZCaW1pTVh0RUJzdDdGdHlPYTgK2mlgcX2kEc8+2UDdBnhUm6IIuh8V6agW
ooxH9OEPXUVI/4JcDo4v8ZUhAyU1ehLH0Ef7PJCChOZe2KZmWSNbhA== ooxH9OEPXUVI/4JcDo4v8ZUhAyU1ehLH0Ef7PJCChOZe2KZmWSNbhA==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2025-12-04T12:35:00Z" lastmodified: "2025-12-25T10:37:16Z"
mac: ENC[AES256_GCM,data:hiEzLAEtU82Be/+nuMv10/ex/ZacXkNR9LkxdBn/x3kY/0uwHSDI9LGjn0b0/KWIg5zLoxV+zPZEBJQhN4QcRzDT6538zwc0yTv9fkFS0NUF5GchHi8Is6EjjHANbSLe3MEwFumKjx3Lm8AyMjcOXiCckzo4aXV98SHZW9EMVbQ=,iv:Nzzlfsm2aMSVa6NNh4ar67J5dzheWRIVLHSUu5ndjvE=,tag:jO8x2LUpP75g7cXyIYDfQw==,type:str] mac: ENC[AES256_GCM,data:ffiDjDbD/BkzBt6zzly3vDtRbRSfpgGmRIjVarPvTuc/GLUPfUpDzibT27E7LI4aBK8Utt9CCip18zmtRKF4z4h4GfHrp0pb6PipyT43+bXqzmsBrCENDiJhiSYhc6VcpA1Xn18Ce8pMaIHkYrrABqtHxU9ML3NEy6vQgN4jim8=,iv:AnWInBNkjBteWhNPASwawH+6m9yopFnYFIh7dP1jVHo=,tag:6WBLuVOXrj1jOhOHUQ7cYA==,type:str]
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted
version: 3.11.0 version: 3.11.0

View File

@@ -55,4 +55,11 @@
CMAKE_EXPORT_COMPILE_COMMANDS = "1"; CMAKE_EXPORT_COMPILE_COMMANDS = "1";
hardeningDisable = [ "all" ]; hardeningDisable = [ "all" ];
}; };
misskey-forwarder = pkgs.mkShell.override { stdenv = pkgs.clang18Stdenv; }
{
inputsFrom = [ pkgs.localPackages.misskey-forwarder ];
packages = [ pkgs.llvmPackages_18.clang-tools ];
CMAKE_EXPORT_COMPILE_COMMANDS = "1";
hardeningDisable = [ "all" ];
};
} }

View File

@@ -27,6 +27,7 @@ let
"git" "grafana" "peertube" "send" "vikunja" "xservernas" "freshrss" "huginn" "nextcloud" "git" "grafana" "peertube" "send" "vikunja" "xservernas" "freshrss" "huginn" "nextcloud"
"rsshub" "vaultwarden" "webdav" "synapse" "misskey" "api" "rsshub" "vaultwarden" "webdav" "synapse" "misskey" "api"
]; ];
"tinc0.pc" = [ "misskey-forwarder" ];
}; };
a = a =
{ {

View File

@@ -0,0 +1,53 @@
inputs:
{
options.nixos.services.misskey-forwarder = let inherit (inputs.lib) mkOption types; in mkOption
{ type = types.nullOr (types.submodule {}); default = null; };
config = let inherit (inputs.config.nixos.services) misskey-forwarder; in inputs.lib.mkIf (misskey-forwarder != null)
{
users =
{
users.misskey-forwarder =
{ uid = inputs.config.nixos.user.uid.misskey-forwarder; group = "misskey-forwarder"; isSystemUser = true; };
groups.misskey-forwarder.gid = inputs.config.nixos.user.gid.misskey-forwarder;
};
systemd =
{
services.misskey-forwarder =
{
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig =
{
User = inputs.config.users.users.misskey-forwarder.name;
Group = inputs.config.users.users.misskey-forwarder.group;
ExecStart =
let forwarder = inputs.pkgs.localPackages.misskey-forwarder.override
{ configFile = inputs.config.nixos.system.sops.templates."misskey-forwarder/config.yml".path; };
in "${forwarder}/bin/misskey-forwarder";
};
};
};
nixos =
{
services.nginx.https."misskey-forwarder.chn.moe".location."/".proxy.upstream = "http://127.0.0.1:9173";
system.sops =
{
templates."misskey-forwarder/config.yml" =
{
owner = "misskey-forwarder";
content =
let inherit (inputs.config.nixos.system.sops) placeholder;
in builtins.toJSON
{
Secret = placeholder."misskey-forwarder/secret";
TelegramBotToken = placeholder."misskey-forwarder/telegramBotToken";
TelegramChatId = placeholder."misskey-forwarder/telegramChatId";
ServerPort = 9173;
};
};
secrets = inputs.lib.genAttrs' [ "secret" "telegramBotToken" "telegramChatId" ]
(n: inputs.lib.nameValuePair "misskey-forwarder/${n}" {});
};
};
};
}

View File

@@ -56,6 +56,7 @@ inputs:
hpcstat = 2011; hpcstat = 2011;
speedtest = 2012; speedtest = 2012;
tailscale = 2013; tailscale = 2013;
misskey-forwarder = 2014;
}; };
}; };
gid = mkOption gid = mkOption

View File

@@ -144,6 +144,7 @@ inputs: rec
buildProxy = inputs.pkgs.lib.mkBuildproxy ./pybinding/proxy.nix; buildProxy = inputs.pkgs.lib.mkBuildproxy ./pybinding/proxy.nix;
}; };
brokenaxes = inputs.pkgs.python3Packages.callPackage ./brokenaxes.nix { src = inputs.topInputs.brokenaxes; }; brokenaxes = inputs.pkgs.python3Packages.callPackage ./brokenaxes.nix { src = inputs.topInputs.brokenaxes; };
misskey-forwarder = inputs.pkgs.callPackage ./misskey-forwarder { inherit biu; stdenv = inputs.pkgs.clang18Stdenv; };
fromYaml = content: builtins.fromJSON (builtins.readFile fromYaml = content: builtins.fromJSON (builtins.readFile
(inputs.pkgs.runCommand "toJSON" {} (inputs.pkgs.runCommand "toJSON" {}

View File

@@ -0,0 +1 @@
use flake .#misskey-forwarder

View File

@@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.14)
project(misskey-forwarder VERSION 0.0.0 LANGUAGES CXX)
enable_testing()
include(GNUInstallDirs)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message("Setting build type to 'Release' as none was specified.")
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
find_package(biu REQUIRED)
find_package(httplib REQUIRED)
add_executable(misskey-forwarder src/main.cpp)
target_link_libraries(misskey-forwarder PRIVATE biu::biu httplib::httplib)
target_compile_features(misskey-forwarder PRIVATE cxx_std_23)
target_compile_definitions(misskey-forwarder PRIVATE FORWARDER_CONFIG_FILE="${FORWARDER_CONFIG_FILE}")
install(TARGETS misskey-forwarder RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
get_property(ImportedTargets DIRECTORY "${CMAKE_SOURCE_DIR}" PROPERTY IMPORTED_TARGETS)
message("Imported targets: ${ImportedTargets}")
message("List of compile features: ${CMAKE_CXX_COMPILE_FEATURES}")
message("CMake build type: ${CMAKE_BUILD_TYPE}")

View File

@@ -0,0 +1,8 @@
{ lib, stdenv, cmake, pkg-config, biu, configFile ? null, httplib }: stdenv.mkDerivation
{
name = "misskey-forwarder";
src = ./.;
buildInputs = [ biu httplib ];
nativeBuildInputs = [ cmake pkg-config ];
cmakeFlags = lib.optional (configFile != null) [ "-DFORWARDER_CONFIG_FILE=${configFile}" ];
}

View File

@@ -0,0 +1,60 @@
# include <biu.hpp>
# include <httplib.h>
# include <tgbot/tgbot.h>
# ifndef FORWARDER_CONFIG_FILE
# define FORWARDER_CONFIG_FILE "./config.yml"
# endif
int main()
{
using namespace biu::literals;
biu::Logger::Guard log;
struct Config
{
std::string Secret;
std::string TelegramBotToken;
std::string TelegramChatId;
int ServerPort;
};
auto config = YAML::LoadFile(FORWARDER_CONFIG_FILE).as<Config>();
biu::Logger::try_exec([&]
{
httplib::Server svr;
svr.Post("/", [&](const httplib::Request& req, httplib::Response& res)
{
biu::Logger::try_exec([&]
{
if (req.get_header_value("x-misskey-hook-secret") != config.Secret)
throw std::runtime_error("Invalid secret key.");
struct Content
{
std::string type, server;
struct { struct
{
std::string text, visibility;
struct Renote { std::string id; };
std::optional<Renote> renote;
} note; } body;
};
auto content = YAML::Load(req.body).as<Content>();
if (content.type != "note" || content.body.note.visibility != "public") return;
std::string text = content.body.note.text;
if (content.body.note.renote)
text += "\n🔁 Renote: https://{}/notes/{}"_f(content.server, content.body.note.renote->id);
TgBot::Bot bot(config.TelegramBotToken);
bot.getApi().sendMessage(config.TelegramChatId, text);
res.status = 200;
res.body = "OK";
});
});
svr.listen("0.0.0.0", config.ServerPort);
return 0;
});
}