Merge branch 'staging/discord'
This commit is contained in:
@@ -19,7 +19,7 @@ creation_rules:
|
|||||||
- *host_lappy
|
- *host_lappy
|
||||||
- *host_servo
|
- *host_servo
|
||||||
- *host_moby
|
- *host_moby
|
||||||
- path_regex: secrets/servo.yaml$
|
- path_regex: secrets/servo*
|
||||||
key_groups:
|
key_groups:
|
||||||
- age:
|
- age:
|
||||||
- *user_desko_colin
|
- *user_desko_colin
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
# TODO: mode? could be more granular
|
# TODO: mode? could be more granular
|
||||||
{ user = "261"; group = "261"; directory = "/var/lib/ipfs"; }
|
{ user = "261"; group = "261"; directory = "/var/lib/ipfs"; }
|
||||||
];
|
];
|
||||||
services.ipfs.enable = true;
|
# services.ipfs.enable = true;
|
||||||
services.ipfs.localDiscovery = true;
|
services.ipfs.localDiscovery = true;
|
||||||
services.ipfs.swarmAddress = [
|
services.ipfs.swarmAddress = [
|
||||||
# "/dns4/ipfs.uninsane.org/tcp/4001"
|
# "/dns4/ipfs.uninsane.org/tcp/4001"
|
||||||
|
@@ -1,12 +1,13 @@
|
|||||||
# docs: https://nixos.wiki/wiki/Matrix
|
# docs: https://nixos.wiki/wiki/Matrix
|
||||||
# docs: https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-synapse
|
# docs: https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-synapse
|
||||||
{ config, ... }:
|
{ config, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
sane.impermanence.service-dirs = [
|
sane.impermanence.service-dirs = [
|
||||||
# TODO: mode?
|
# TODO: mode?
|
||||||
# user and group are both "matrix-appservice-irc"
|
# user and group are both "matrix-appservice-irc"
|
||||||
{ user = "993"; group = "992"; directory = "/var/lib/matrix-appservice-irc"; }
|
{ user = "993"; group = "992"; directory = "/var/lib/matrix-appservice-irc"; }
|
||||||
|
{ user = "matrix-appservice-discord"; group = "matrix-appservice-discord"; directory = "/var/lib/matrix-appservice-discord"; }
|
||||||
{ user = "224"; group = "224"; directory = "/var/lib/matrix-synapse"; }
|
{ user = "224"; group = "224"; directory = "/var/lib/matrix-synapse"; }
|
||||||
];
|
];
|
||||||
services.matrix-synapse.enable = true;
|
services.matrix-synapse.enable = true;
|
||||||
@@ -64,6 +65,7 @@
|
|||||||
# ''];
|
# ''];
|
||||||
services.matrix-synapse.settings.app_service_config_files = [
|
services.matrix-synapse.settings.app_service_config_files = [
|
||||||
"/var/lib/matrix-appservice-irc/registration.yml" # auto-created by irc appservice
|
"/var/lib/matrix-appservice-irc/registration.yml" # auto-created by irc appservice
|
||||||
|
"/var/lib/matrix-appservice-discord/discord-registration.yaml" # auto-created by discord appservice
|
||||||
];
|
];
|
||||||
|
|
||||||
# new users may be registered on the CLI:
|
# new users may be registered on the CLI:
|
||||||
@@ -78,6 +80,58 @@
|
|||||||
# create a token with limited uses:
|
# create a token with limited uses:
|
||||||
# curl -d '{ "uses_allowed": 1 }' --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens/new
|
# curl -d '{ "uses_allowed": 1 }' --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens/new
|
||||||
|
|
||||||
|
# Discord bridging
|
||||||
|
# docs: https://github.com/matrix-org/matrix-appservice-discord
|
||||||
|
services.matrix-appservice-discord.enable = true;
|
||||||
|
services.matrix-appservice-discord.settings = {
|
||||||
|
bridge = {
|
||||||
|
homeserverUrl = "http://127.0.0.1:8008";
|
||||||
|
domain = "uninsane.org";
|
||||||
|
adminMxid = "admin.matrix@uninsane.org";
|
||||||
|
# self-service bridging is when a Matrix user bridges by DMing @_discord_bot:<HS>
|
||||||
|
# i don't know what the alternative is :?
|
||||||
|
enableSelfServiceBridging = true;
|
||||||
|
presenceInterval = 30000; # milliseconds
|
||||||
|
# allows matrix users to search for Discord channels (somehow?)
|
||||||
|
disablePortalBridging = false;
|
||||||
|
# disableReadReceipts = true;
|
||||||
|
# these are Matrix -> Discord
|
||||||
|
disableJoinLeaveNotifications = true;
|
||||||
|
disableInviteNotifications = true;
|
||||||
|
disableRoomTopicNotifications = true;
|
||||||
|
};
|
||||||
|
# these are marked as required in the yaml schema
|
||||||
|
auth = {
|
||||||
|
# apparently not needed if you provide them as env vars (below).
|
||||||
|
# clientId = "FILLME";
|
||||||
|
# botToken = "FILLME";
|
||||||
|
usePrivilegedIntents = false;
|
||||||
|
};
|
||||||
|
logging = {
|
||||||
|
# silly, verbose, info, http, warn, error, silent
|
||||||
|
console = "verbose";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# contains what's ordinarily put into auth.clientId, auth.botToken
|
||||||
|
# i.e. `APPSERVICE_DISCORD_AUTH_CLIENT_I_D=...` and `APPSERVICE_DISCORD_AUTH_BOT_TOKEN=...`
|
||||||
|
services.matrix-appservice-discord.environmentFile = config.sops.secrets.matrix_appservice_discord_env.path;
|
||||||
|
|
||||||
|
systemd.services.matrix-appservice-discord.serviceConfig = {
|
||||||
|
# fix up to not use /var/lib/private, but just /var/lib
|
||||||
|
DynamicUser = lib.mkForce false;
|
||||||
|
User = "matrix-appservice-discord";
|
||||||
|
Group = "matrix-appservice-discord";
|
||||||
|
};
|
||||||
|
users.groups.matrix-appservice-discord = {};
|
||||||
|
users.users.matrix-appservice-discord = {
|
||||||
|
description = "User for the Matrix-Discord bridge";
|
||||||
|
group = "matrix-appservice-discord";
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
users.users.matrix-appservice-discord.uid = 2134; # TODO: move to allocations
|
||||||
|
users.groups.matrix-appservice-discord.gid = 2134; # TODO
|
||||||
|
|
||||||
|
|
||||||
# IRC bridging
|
# IRC bridging
|
||||||
# note: Rizon allows only FOUR simultaneous IRC connections per IP: https://wiki.rizon.net/index.php?title=Connection/Session_Limit_Exemptions
|
# note: Rizon allows only FOUR simultaneous IRC connections per IP: https://wiki.rizon.net/index.php?title=Connection/Session_Limit_Exemptions
|
||||||
# Rizon supports CertFP for auth: https://wiki.rizon.net/index.php?title=CertFP
|
# Rizon supports CertFP for auth: https://wiki.rizon.net/index.php?title=CertFP
|
||||||
@@ -167,4 +221,9 @@
|
|||||||
sopsFile = ../../../../secrets/servo.yaml;
|
sopsFile = ../../../../secrets/servo.yaml;
|
||||||
owner = config.users.users.matrix-synapse.name;
|
owner = config.users.users.matrix-synapse.name;
|
||||||
};
|
};
|
||||||
|
sops.secrets.matrix_appservice_discord_env = {
|
||||||
|
sopsFile = ../../../../secrets/servo/matrix_appservice_discord_env.bin;
|
||||||
|
owner = config.users.users.matrix-appservice-discord.name;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
13
pkgs/matrix-appservice-discord/01-puppet.patch
Normal file
13
pkgs/matrix-appservice-discord/01-puppet.patch
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
diff --git a/src/clientfactory.ts b/src/clientfactory.ts
|
||||||
|
index b7fea47..587acfd 100644
|
||||||
|
--- a/src/clientfactory.ts
|
||||||
|
+++ b/src/clientfactory.ts
|
||||||
|
@@ -53,7 +53,7 @@ export class DiscordClientFactory {
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
- await this.botClient.login(this.config.botToken, true);
|
||||||
|
+ await this.botClient.login(this.config.botToken, false);
|
||||||
|
log.info("Waiting for shardReady signal");
|
||||||
|
await waitPromise;
|
||||||
|
log.info("Got shardReady signal");
|
16
pkgs/matrix-appservice-discord/02-auto-approve.patch
Normal file
16
pkgs/matrix-appservice-discord/02-auto-approve.patch
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
diff --git a/src/provisioner.ts b/src/provisioner.ts
|
||||||
|
index c1568af..28a44c5 100644
|
||||||
|
--- a/src/provisioner.ts
|
||||||
|
+++ b/src/provisioner.ts
|
||||||
|
@@ -99,8 +99,9 @@
|
||||||
|
this.pendingRequests.set(channelId, approveFn);
|
||||||
|
setTimeout(() => approveFn(false, true), timeout);
|
||||||
|
|
||||||
|
- await channel.send(`${requestor} on matrix would like to bridge this channel. Someone with permission` +
|
||||||
|
- " to manage webhooks please reply with `!matrix approve` or `!matrix deny` in the next 5 minutes");
|
||||||
|
+ // await channel.send(`${requestor} on matrix would like to bridge this channel. Someone with permission` +
|
||||||
|
+ // " to manage webhooks please reply with `!matrix approve` or `!matrix deny` in the next 5 minutes");
|
||||||
|
+ approveFn(true);
|
||||||
|
return await deferP;
|
||||||
|
|
||||||
|
}
|
14
pkgs/matrix-appservice-discord/03-no-edits.patch
Normal file
14
pkgs/matrix-appservice-discord/03-no-edits.patch
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
diff --git a/src/bot.ts b/src/bot.ts
|
||||||
|
index 8bc73d4..1e6ea67 100644
|
||||||
|
--- a/src/bot.ts
|
||||||
|
+++ b/src/bot.ts
|
||||||
|
@@ -568,7 +568,8 @@ export class DiscordBot {
|
||||||
|
}
|
||||||
|
const link = `https://discord.com/channels/${chan.guild.id}/${chan.id}/${editEventId}`;
|
||||||
|
embedSet.messageEmbed.description = `[Edit](${link}): ${embedSet.messageEmbed.description}`;
|
||||||
|
- await this.send(embedSet, opts, roomLookup, event);
|
||||||
|
+ log.warn("not editing sent Matrix -> Discord message");
|
||||||
|
+ // await this.send(embedSet, opts, roomLookup, event);
|
||||||
|
} catch (err) {
|
||||||
|
// throw wrapError(err, Unstable.ForeignNetworkError, "Couldn't edit message");
|
||||||
|
log.warn(`Failed to edit message ${event.event_id}`);
|
88
pkgs/matrix-appservice-discord/04-no-kickbans.patch
Normal file
88
pkgs/matrix-appservice-discord/04-no-kickbans.patch
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
diff --git a/src/bot.ts b/src/bot.ts
|
||||||
|
index 8bc73d4..1e6ea67 100644
|
||||||
|
--- a/src/bot.ts
|
||||||
|
+++ b/src/bot.ts
|
||||||
|
@@ -795,82 +796,7 @@ export class DiscordBot {
|
||||||
|
roomId: string, kickeeUserId: string, kicker: string, kickban: "leave"|"ban",
|
||||||
|
previousState: string, reason?: string,
|
||||||
|
) {
|
||||||
|
- const restore = kickban === "leave" && previousState === "ban";
|
||||||
|
- const client = await this.clientFactory.getClient(kicker);
|
||||||
|
- let channel: Discord.Channel;
|
||||||
|
- try {
|
||||||
|
- channel = await this.GetChannelFromRoomId(roomId, client);
|
||||||
|
- } catch (ex) {
|
||||||
|
- log.error("Failed to get channel for ", roomId, ex);
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
- if (channel.type !== "text") {
|
||||||
|
- log.warn("Channel was not a text channel");
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
- const tchan = (channel as Discord.TextChannel);
|
||||||
|
- const kickeeUser = await this.GetDiscordUserOrMember(
|
||||||
|
- kickeeUserId.substring("@_discord_".length, kickeeUserId.indexOf(":") - 1),
|
||||||
|
- tchan.guild.id,
|
||||||
|
- );
|
||||||
|
- if (!kickeeUser) {
|
||||||
|
- log.error("Could not find discord user for", kickeeUserId);
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
- const kickee = kickeeUser as Discord.GuildMember;
|
||||||
|
- let res: Discord.Message;
|
||||||
|
- const botChannel = await this.GetChannelFromRoomId(roomId) as Discord.TextChannel;
|
||||||
|
- if (restore) {
|
||||||
|
- await tchan.overwritePermissions([
|
||||||
|
- {
|
||||||
|
- allow: ["SEND_MESSAGES", "VIEW_CHANNEL"],
|
||||||
|
- id: kickee.id,
|
||||||
|
- }],
|
||||||
|
- `Unbanned.`,
|
||||||
|
- );
|
||||||
|
- this.channelLock.set(botChannel.id);
|
||||||
|
- res = await botChannel.send(
|
||||||
|
- `${kickee} was unbanned from this channel by ${kicker}.`,
|
||||||
|
- ) as Discord.Message;
|
||||||
|
- this.sentMessages.push(res.id);
|
||||||
|
- this.channelLock.release(botChannel.id);
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
- const existingPerms = tchan.permissionsFor(kickee);
|
||||||
|
- if (existingPerms && existingPerms.has(Discord.Permissions.FLAGS.VIEW_CHANNEL as number) === false ) {
|
||||||
|
- log.warn("User isn't allowed to read anyway.");
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
- const word = `${kickban === "ban" ? "banned" : "kicked"}`;
|
||||||
|
- this.channelLock.set(botChannel.id);
|
||||||
|
- res = await botChannel.send(
|
||||||
|
- `${kickee} was ${word} from this channel by ${kicker}.`
|
||||||
|
- + (reason ? ` Reason: ${reason}` : ""),
|
||||||
|
- ) as Discord.Message;
|
||||||
|
- this.sentMessages.push(res.id);
|
||||||
|
- this.channelLock.release(botChannel.id);
|
||||||
|
- log.info(`${word} ${kickee}`);
|
||||||
|
-
|
||||||
|
- await tchan.overwritePermissions([
|
||||||
|
- {
|
||||||
|
- deny: ["SEND_MESSAGES", "VIEW_CHANNEL"],
|
||||||
|
- id: kickee.id,
|
||||||
|
- }],
|
||||||
|
- `Matrix user was ${word} by ${kicker}.`,
|
||||||
|
- );
|
||||||
|
- if (kickban === "leave") {
|
||||||
|
- // Kicks will let the user back in after ~30 seconds.
|
||||||
|
- setTimeout(async () => {
|
||||||
|
- log.info(`Kick was lifted for ${kickee.displayName}`);
|
||||||
|
- await tchan.overwritePermissions([
|
||||||
|
- {
|
||||||
|
- allow: ["SEND_MESSAGES", "VIEW_CHANNEL"],
|
||||||
|
- id: kickee.id,
|
||||||
|
- }],
|
||||||
|
- `Lifting kick since duration expired.`,
|
||||||
|
- );
|
||||||
|
- }, this.config.room.kickFor);
|
||||||
|
- }
|
||||||
|
+ return; // this is about letting Discord users know when Matrix users are kicked/banned
|
||||||
|
}
|
||||||
|
|
||||||
|
public async GetEmojiByMxc(mxc: string): Promise<DbEmoji> {
|
13
pkgs/matrix-appservice-discord/05-no-meta.patch
Normal file
13
pkgs/matrix-appservice-discord/05-no-meta.patch
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
diff --git a/src/matrixeventprocessor.ts b/src/matrixeventprocessor.ts
|
||||||
|
index f1f4611..7b57ff3 100644
|
||||||
|
--- a/src/matrixeventprocessor.ts
|
||||||
|
+++ b/src/matrixeventprocessor.ts
|
||||||
|
@@ -278,6 +278,8 @@ export class MatrixEventProcessor {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ return; // disable all meta notifications
|
||||||
|
+
|
||||||
|
msg += " on Matrix.";
|
||||||
|
const channel = await this.discord.GetChannelFromRoomId(event.room_id) as Discord.TextChannel;
|
||||||
|
await this.discord.sendAsBot(msg, channel, event);
|
19
pkgs/matrix-appservice-discord/default.nix
Normal file
19
pkgs/matrix-appservice-discord/default.nix
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{ pkgs }:
|
||||||
|
|
||||||
|
(pkgs.matrix-appservice-discord.overrideAttrs (upstream: {
|
||||||
|
# 2022-10-05: the service can't login as an ordinary user unless i change the source
|
||||||
|
doCheck = false;
|
||||||
|
patches = (upstream.patches or []) ++ [
|
||||||
|
# don't register with better-discord as a bot
|
||||||
|
./01-puppet.patch
|
||||||
|
# don't ask Discord admin for approval before bridging
|
||||||
|
./02-auto-approve.patch
|
||||||
|
# disable Matrix -> Discord edits because they do not fit Discord semantics
|
||||||
|
./03-no-edits.patch
|
||||||
|
# we don't want to notify Discord users that a Matrix user was kicked/banned
|
||||||
|
./04-no-kickbans.patch
|
||||||
|
# don't notify Discord users when the Matrix room changes (name, topic, membership)
|
||||||
|
./05-no-meta.patch
|
||||||
|
];
|
||||||
|
}))
|
||||||
|
|
@@ -27,6 +27,7 @@
|
|||||||
pleroma = prev.callPackage ./pleroma { };
|
pleroma = prev.callPackage ./pleroma { };
|
||||||
# jackett doesn't allow customization of the bind address: this will probably always be here.
|
# jackett doesn't allow customization of the bind address: this will probably always be here.
|
||||||
jackett = prev.callPackage ./jackett { pkgs = prev; };
|
jackett = prev.callPackage ./jackett { pkgs = prev; };
|
||||||
|
matrix-appservice-discord = prev.callPackage ./matrix-appservice-discord { pkgs = prev; };
|
||||||
# mozilla keeps nerfing itself and removing configuration options
|
# mozilla keeps nerfing itself and removing configuration options
|
||||||
firefox-unwrapped = prev.callPackage ./firefox-unwrapped { pkgs = prev; };
|
firefox-unwrapped = prev.callPackage ./firefox-unwrapped { pkgs = prev; };
|
||||||
# fix abrupt HDD poweroffs as during reboot. patching systemd requires rebuilding nearly every package.
|
# fix abrupt HDD poweroffs as during reboot. patching systemd requires rebuilding nearly every package.
|
||||||
|
28
secrets/servo/matrix_appservice_discord_env.bin
Normal file
28
secrets/servo/matrix_appservice_discord_env.bin
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"data": "ENC[AES256_GCM,data:7j1l4XJ8cp8MVuSmOedOZwGDWV11hmwFyLW43ixUBaZLWbUZ6Z4P4Gt+o7bj8gc/X8aiPV8sxAR/jY28Sc5DIaAnkKnXjesPVlG0c3oRAsXemKGX8fANkoNX5iEPbWAkFiJdLS6Fgdv2g4z6DQ4odvZQKrMchx8MPYq8icBvvbhKiGs5xo+MGrMBVRCZOERM2FJSy/q9zLv6hU5SfnnYDTMt,iv:poHHiCs0YOCv74dQ2kyXogdgTUqmKRgGq2r7lcxe4bQ=,tag:rz1/FLC5Q8S13TTWNKcYyQ==,type:str]",
|
||||||
|
"sops": {
|
||||||
|
"kms": null,
|
||||||
|
"gcp_kms": null,
|
||||||
|
"azure_kv": null,
|
||||||
|
"hc_vault": null,
|
||||||
|
"age": [
|
||||||
|
{
|
||||||
|
"recipient": "age1tnl4jfgacwkargzeqnhzernw29xx8mkv73xh6ufdyde6q7859slsnzf24x",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2TjVWenJkYVdjeExzYjVj\nUVdFeUdMRUtwOWJNYUx6dFRWRXdEUWJhdkVFClM1UnhtWndYbE91RCtVRnl4TGp4\nZHNJNUliOWhqcUorZVBEQWR0eXZaMVEKLS0tIDdsVFJ2bmdNeVk5b3FJVDQ3T1BG\nU0taQlA1QVEvYVJweDQ5L2YwTmo2ek0K+nbzpIpjAhRgJ5Lw+mx/doGMjw0aMNkZ\n5sAnPJo88Sa/TW3qBN48xFBMLWMp/SKs2JTaMu0xW0u2SkQX38TLlw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recipient": "age1z8fauff34cdecr6sjkre260luzxcca05kpcwvhx988d306tpcejsp63znu",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyUFBSYVJZUmRBcGJXclNP\nRDRUZnRKMmYwdFhQcE1oWUhrZGxNTk5YOFIwCldUMW92NGl0VVBsS0JtYjJOTW9E\nK2ZZdm9GK3FOMitUdEU3QStsR2svQWMKLS0tIE9SWXAzVndsdGY3Uzh2eHpBRjdO\nTVc4cWNDUWRuSWRmZC8rK1ZFS2l4WEkKQR9mApDjb0k14W3jK+CEz3Dez6wSBpg+\nZ7uUfSbPXFxRxvNEascRn/+EHPcd/A7MZjViDUyWVcP6fSMPsQvxhw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recipient": "age1tzlyex2z6t88tg9h82943e39shxhmqeyr7ywhlwpdjmyqsndv3qq27x0rf",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkWHlteTRDcHRneW9hbzlh\nMHBjZ2RHeDBIbDM2QXVxK09mcERVSUliVWw0Ckg1dGFkUUxPQW1HcDFXcEEyejFD\nWW5qUkNwRkdIdjRiTFJNd0Q5NWpLUUEKLS0tIG1wTnk1aEhudm9VZjZRVGRWWnR0\nVHlFbUJHaitadDVOSG1FMTBqeHJGV0kKAjuuw3j4dx3QfNcjyl8XCP9Q6oOkLZBN\nsW7uCqbVgBCG+uIggwefLWAy8g6PYlLj0aumgLPYVsXShbQYi32m/g==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastmodified": "2022-10-06T05:07:20Z",
|
||||||
|
"mac": "ENC[AES256_GCM,data:9WR8xfs5XIkWxDlJVX1EiSJBLBgWMR99PJJXCK9RcbuChK7QvjWjEflwq419qeNbMWdHLkUwSQrBsoHomaiGWFOPZ0C8bqcqDl0zzXMk7nBxM4UgTjRLmML2tdI2bCS0DC0AtytThYPvkW+JHgKB6bOAEw/bVWVP4YJQKWEf6FY=,iv:nG+J7jCdqZHp6x6Vlvye7BbK7YSl0Y9cjTWbW/BZLxo=,tag:OWqXktZE52Q3j7D2KG+vHw==,type:str]",
|
||||||
|
"pgp": null,
|
||||||
|
"unencrypted_suffix": "_unencrypted",
|
||||||
|
"version": "3.7.3"
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user