Initial commit
commit
0dd7fb7ac0
@ -0,0 +1,21 @@
|
|||||||
|
# Colmena NixOS Config Template
|
||||||
|
|
||||||
|
* user gpg-keys (for them to be able to decrypt the secrets): `secrets/.gpg-id`
|
||||||
|
* collect/generate host gpg-keys: `./lib/create-keys.sh`
|
||||||
|
* edit stuff in password store: `./lib/pass.sh`
|
||||||
|
|
||||||
|
## How to deploy
|
||||||
|
```
|
||||||
|
./deploy.sh apply switch --on vpn7
|
||||||
|
```
|
||||||
|
|
||||||
|
or to deploy all gateways (all hosts with the gateway-tag):
|
||||||
|
|
||||||
|
```
|
||||||
|
./deploy.sh apply switch --on gateway
|
||||||
|
```
|
||||||
|
|
||||||
|
There is a special case for the nixdeploy-host:
|
||||||
|
```
|
||||||
|
./deploy.sh apply-local --node nixdeploy
|
||||||
|
```
|
@ -0,0 +1,44 @@
|
|||||||
|
{ pkgs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
nix = {
|
||||||
|
package = pkgs.nixFlakes;
|
||||||
|
extraOptions = ''
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
'';
|
||||||
|
trustedUsers = [ "root" "@wheel" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.openssh.enable = true;
|
||||||
|
services.openssh.permitRootLogin = "without-password";
|
||||||
|
|
||||||
|
security.sudo.wheelNeedsPassword = false;
|
||||||
|
|
||||||
|
time.timeZone = "Europe/Berlin";
|
||||||
|
|
||||||
|
networking.firewall.logRefusedConnections = false;
|
||||||
|
|
||||||
|
programs.mtr.enable = true;
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
bind.dnsutils
|
||||||
|
colmena
|
||||||
|
git
|
||||||
|
gnupg
|
||||||
|
htop
|
||||||
|
rsync
|
||||||
|
tmux
|
||||||
|
wget
|
||||||
|
];
|
||||||
|
|
||||||
|
programs.vim.defaultEditor = true;
|
||||||
|
|
||||||
|
users.users.root = {
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEcOPtW5FWNIdlMQFoqeyA1vHw+cA8ft8oXSbXPzQNL9 n0emis@n0emis.eu"
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC8xqVakxJ+AwcIrS/wyL03N++pE09epwMFlIMXWvlpwwEp1J/0H7nygwxk/9LIZdabs/ETWn0s8oHAkc7YR1c6ajSTCDiZEYATAWt7t8t4Gw/80c8u8T50lIqmiDEEVbOVv3Vta/pAN4hAUp9U5DpYCkQbvF+NKKcK3Yp8d9usNC6ohqgTK+IGAEdMhvpbbNppDMXoWHuynBzUX7TS6ST6yEr0tD+CBbCpbfcMuwTI3lNtfywEVpuFaeHqDZx2QDrEX4bg0dRKgQstbXYdqmBfnOiBpUr8Wyl8U1J24rN+E07pBw/8KDGWbVg19/Ex8o4ht/p5voUfKVjD/DwWXTLntBirjfAgQAm4GH/qP4x3zNiTtlYlQFbXSk6VEVrTrxCB5rTWvGnhg31tk5P3YwvagDmGABazY5s/8tlttSc1yWBctWQJCjxSqcCLekxG4D1rVuGKCKOZgflQ9QFdQlKycInPBek3zi0i3GYkE1YnNFye5ggOnxT8qGuKjfdtZI9qvMJQO8lbEDzbYQvNns1V/k4ZobiihYwrG5TJUzZFEpMYetDK6tI8BRU11d+ja0jWzguj5/7wc0nrr/BiZ8FkAr2fZ60j2aI5kG0s3qjbrQbB/RXaGP9hRU0+480+IokNJJIcjv5iwH5ophdrjC8GH4So2kPPt0NXob1yNysdjw== simeon@noemis.me (OLD)"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.noXlibs = lib.mkForce false;
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
DEPLOY_HOST="nixdeploy.neo.cccgoe.de"
|
||||||
|
|
||||||
|
rsync -r . root@${DEPLOY_HOST}:/root/nixfiles/
|
||||||
|
ssh -tA root@${DEPLOY_HOST} "cd /root/nixfiles && colmena $@"
|
@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"ffnix": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1649686725,
|
||||||
|
"narHash": "sha256-t2ByQJ52I67nxdocQRtYOvBD7ZHNt6wRcWqq79EZmGw=",
|
||||||
|
"owner": "n0emis",
|
||||||
|
"repo": "ffnix",
|
||||||
|
"rev": "bdf5dfb77cd474d7fbddc1297526dc1ce339fdb2",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "n0emis",
|
||||||
|
"ref": "main",
|
||||||
|
"repo": "ffnix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1644229661,
|
||||||
|
"narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1647992509,
|
||||||
|
"narHash": "sha256-AG40Nt5OWz0LBs5p457emOuwLKOvTtcv/2fUdnEN3Ws=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "d2caa9377539e3b5ff1272ac3aa2d15f3081069f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "release-21.11",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"ffnix": "ffnix",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
description = "FFGoe NixOS Config";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/release-21.11";
|
||||||
|
ffnix = {
|
||||||
|
url = "github:n0emis/ffnix/main";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
outputs = { self, nixpkgs, ffnix }: {
|
||||||
|
colmena = {
|
||||||
|
meta = {
|
||||||
|
nixpkgs = import nixpkgs {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
overlays = [
|
||||||
|
ffnix.overlay
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
defaults = { config, lib, name, ... }: {
|
||||||
|
deployment.targetHost = lib.mkDefault (config.networking.hostName + "." + config.networking.domain);
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
(./. + "/hosts/${name}")
|
||||||
|
./common
|
||||||
|
./modules
|
||||||
|
ffnix.nixosModule
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
vpn7 = {
|
||||||
|
deployment.tags = [ "gateway" "legacy" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
nixdeploy = {
|
||||||
|
deployment.allowLocalDeployment = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
testhost = {
|
||||||
|
deployment.targetHost = "10.152.32.1";
|
||||||
|
};
|
||||||
|
|
||||||
|
dfz-el = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
{ config, pkgs, modulesPath, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
(modulesPath + "/virtualisation/lxc-container.nix")
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.hostName = "nixdeploy";
|
||||||
|
networking.domain = "neo.cccgoe.de";
|
||||||
|
|
||||||
|
networking.useNetworkd = true;
|
||||||
|
networking.useDHCP = false;
|
||||||
|
networking.firewall.enable = false;
|
||||||
|
networking.useHostResolvConf = false;
|
||||||
|
|
||||||
|
systemd.suppressedSystemUnits = [
|
||||||
|
"dev-mqueue.mount"
|
||||||
|
"sys-kernel-debug.mount"
|
||||||
|
"sys-fs-fuse-connections.mount"
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.network = {
|
||||||
|
links."10-eth0" = {
|
||||||
|
matchConfig.MACAddress = "02:a6:13:d1:e4:0b";
|
||||||
|
linkConfig.Name = "eth0";
|
||||||
|
};
|
||||||
|
networks."10-eth0" = {
|
||||||
|
name = "eth0";
|
||||||
|
address = [ "192.168.42.101/24" "2a01:4f8:10b:7e1::1:101/64" ];
|
||||||
|
gateway = [ "192.168.42.1" "2a01:4f8:10b:7e1::1:1" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.resolved.dnssec = "false";
|
||||||
|
|
||||||
|
system.stateVersion = "21.11";
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
cd $(dirname $0)/..
|
||||||
|
|
||||||
|
read -r -a HOSTS <<< "$(colmena eval lib/get-hosts.nix | jq -r 'to_entries | map("\(.key) \(.value)") | @tsv')"
|
||||||
|
|
||||||
|
p=0
|
||||||
|
while [ "${HOSTS[$p]}" ]
|
||||||
|
do
|
||||||
|
hostname=${HOSTS[$p]}
|
||||||
|
ssh_host=root@${HOSTS[$p+1]}
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "##### $hostname - $ssh_host"
|
||||||
|
ssh -o ConnectTimeout=10 $ssh_host "echo > /dev/null"
|
||||||
|
rc=$?
|
||||||
|
if [ $rc = 0 ]; then
|
||||||
|
echo "$hostname is online, checking gpg-key"
|
||||||
|
ssh $ssh_host "sudo -u root gpg --fingerprint --with-colons | grep '^fpr' | grep $(cat secrets/$hostname/.gpg-id | tail -n1) > /dev/null"
|
||||||
|
rc=$?
|
||||||
|
else
|
||||||
|
echo "$hostname is offline"
|
||||||
|
rc=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ $rc = 0 ]; then
|
||||||
|
echo "generating gpg-key"
|
||||||
|
mkdir -p secrets/$hostname
|
||||||
|
ssh $ssh_host "sudo rm -rf /root/.gnupg"
|
||||||
|
cat lib/keygen | sed "s/NAME/${hostname}/" | ssh -o RequestTTY=yes $ssh_host "sudo -u root gpg --generate-key --pinentry-mode loopback --batch /dev/stdin"
|
||||||
|
cp secrets/.gpg-id secrets/$hostname/.gpg-id
|
||||||
|
ssh $ssh_host "sudo -u root gpg --fingerprint --with-colons | grep '^fpr' | head -n1 | cut -d: -f10" >> secrets/$hostname/.gpg-id
|
||||||
|
ssh $ssh_host "sudo -u root gpg --fingerprint --with-colons | grep '^fpr' | head -n1 | cut -d: -f10" >> secrets/all/.gpg-id
|
||||||
|
ssh $ssh_host "sudo -u root gpg --export --armor" > secrets/.public-keys/$hostname
|
||||||
|
lib/pass.sh init -p $hostname $(cat secrets/$hostname/.gpg-id);
|
||||||
|
lib/pass.sh init -p all $(cat secrets/all/.gpg-id);
|
||||||
|
else
|
||||||
|
echo "key does already exist..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
let p=p+2
|
||||||
|
done
|
||||||
|
|
@ -0,0 +1,3 @@
|
|||||||
|
{ nodes, pkgs, lib, ... }:
|
||||||
|
# Feels like a NixOS module - But you can return any JSON-serializable value
|
||||||
|
lib.attrsets.mapAttrs (k: v: v.config.deployment.targetHost) nodes
|
@ -0,0 +1,11 @@
|
|||||||
|
%echo Generating ed25519 primary and cv25519 subkey
|
||||||
|
Key-Type: eddsa
|
||||||
|
Key-Curve: Ed25519
|
||||||
|
Key-Usage: sign
|
||||||
|
Name-Real: NAME
|
||||||
|
Subkey-Type: ecdh
|
||||||
|
Subkey-Curve: Curve25519
|
||||||
|
Expire-Date: 0
|
||||||
|
%no-protection
|
||||||
|
%commit
|
||||||
|
%echo done
|
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
cd $(dirname $0)/..
|
||||||
|
|
||||||
|
for key in secrets/.public-keys/*
|
||||||
|
do
|
||||||
|
gpg --import "$key" 2>/dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
export PASSWORD_STORE_GPG_OPTS="--trust-model always"
|
||||||
|
export PASSWORD_STORE_DIR="$PWD/secrets"
|
||||||
|
pass $@
|
||||||
|
|
@ -0,0 +1,7 @@
|
|||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./secrets
|
||||||
|
];
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
secret-file = types.submodule ({ ... }@moduleAttrs: {
|
||||||
|
options = {
|
||||||
|
name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = moduleAttrs.config._module.args.name;
|
||||||
|
};
|
||||||
|
path = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
readOnly = true;
|
||||||
|
default = "/run/secrets/${removeSuffix ".gpg" (baseNameOf moduleAttrs.config.source-path)}";
|
||||||
|
};
|
||||||
|
mode = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "0400";
|
||||||
|
};
|
||||||
|
owner = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "root";
|
||||||
|
};
|
||||||
|
group-name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "root";
|
||||||
|
};
|
||||||
|
source-path = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = pkgs.copyPathToStore "${toString ../../secrets}/${config.networking.hostName}/${moduleAttrs.config.name}.gpg";
|
||||||
|
};
|
||||||
|
encrypted = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
enabledFiles = filterAttrs (n: file: file.enable) config.petabyte.secrets;
|
||||||
|
|
||||||
|
mkDecryptSecret = file: pkgs.writeScript "decrypt-secret-${removeSuffix ".gpg" (baseNameOf file.source-path)}.sh" ''
|
||||||
|
#!${pkgs.runtimeShell}
|
||||||
|
set -eu pipefail
|
||||||
|
if [ ! -f "${file.path}" ]; then
|
||||||
|
umask 0077
|
||||||
|
echo "${file.source-path} -> ${file.path}"
|
||||||
|
${if file.encrypted then ''
|
||||||
|
${pkgs.gnupg}/bin/gpg --decrypt ${escapeShellArg file.source-path} > ${file.path}
|
||||||
|
'' else ''
|
||||||
|
cat ${escapeShellArg file.source-path} > ${file.path}
|
||||||
|
''}
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
mkSetupSecret = file: pkgs.writeScript "setup-secret-${removeSuffix ".gpg" (baseNameOf file.source-path)}.sh" ''
|
||||||
|
#!${pkgs.runtimeShell}
|
||||||
|
set -eu pipefail
|
||||||
|
chown ${escapeShellArg file.owner}:${escapeShellArg file.group-name} ${escapeShellArg file.path}
|
||||||
|
chmod ${escapeShellArg file.mode} ${escapeShellArg file.path}
|
||||||
|
'';
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.petabyte.secrets = mkOption {
|
||||||
|
type = with types; attrsOf secret-file;
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
config = mkIf (enabledFiles != {}) {
|
||||||
|
system.activationScripts = let
|
||||||
|
files = unique (map (flip removeAttrs ["_module"]) (attrValues enabledFiles));
|
||||||
|
decrypt = ''
|
||||||
|
function fail() {
|
||||||
|
rm $1
|
||||||
|
echo "failed to decrypt $1"
|
||||||
|
}
|
||||||
|
echo setting up secrets...
|
||||||
|
mkdir -p /run/secrets
|
||||||
|
chown 0:0 /run/secrets
|
||||||
|
chmod 0755 /run/secrets
|
||||||
|
${concatMapStringsSep "\n" (file: ''
|
||||||
|
${mkDecryptSecret file} || fail ${file.path}
|
||||||
|
'') files}
|
||||||
|
'';
|
||||||
|
setup = ''
|
||||||
|
echo setting up secrets...
|
||||||
|
${concatMapStringsSep "\n" (file: ''
|
||||||
|
${mkSetupSecret file} || echo "failed to set up ${file.path}"
|
||||||
|
'') files}
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
decrypt-secrets.text = "source ${pkgs.writeText "setup-secrets.sh" decrypt}";
|
||||||
|
setup-secrets = stringAfter [ "users" "groups" ] "source ${pkgs.writeText "setup-secrets.sh" setup}";
|
||||||
|
users.deps = [ "decrypt-secrets" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
6E10217E3187069E057DF5ABE0262A773B824745
|
@ -0,0 +1,13 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mDMEYiyiyxYJKwYBBAHaRw8BAQdAPsPSocI7hwg1Ll+MQtAkXB97Fs4wS6jAgHJy
|
||||||
|
4tIV6Yq0CW5peGRlcGxveYiQBBMWCAA4FiEERpX3ufdo1Ms5XHiPp9zPzW66SHsF
|
||||||
|
AmIsossCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQp9zPzW66SHvCUQEA
|
||||||
|
wDc+ifC0KX1diclphsmr379u1zIyCgQnzo1CZfzbfksBAMGHrPrGC01Yhijvp8Op
|
||||||
|
97rCKi5Tc9o3pzIGaQhxheMGuDgEYiyiyxIKKwYBBAGXVQEFAQEHQNBwRBfv1C/n
|
||||||
|
Kj7Zwa4tW/oDO/CofWpZc/rBLW2DTQVnAwEIB4h4BBgWCAAgFiEERpX3ufdo1Ms5
|
||||||
|
XHiPp9zPzW66SHsFAmIsossCGwwACgkQp9zPzW66SHtIvgEAm3V0VlCWh3vAu2sS
|
||||||
|
3kolo3C3O8VNljTZpjyHX9uZb0sA/0kjj9ySpLWg9ct1w9Xq1rx8NAqg3717QfEV
|
||||||
|
Eu93PqIH
|
||||||
|
=sw4f
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
@ -0,0 +1,13 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mDMEYiyjMBYJKwYBBAHaRw8BAQdA6Eqvi71nq1N0YXSv2H7bQPuNhRN71OrMDCav
|
||||||
|
hcuHz9i0BHZwbjeIkAQTFggAOBYhBIkqg13mIq22arDfh8nOp4wJbO8QBQJiLKMw
|
||||||
|
AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEMnOp4wJbO8Q+YQBAPka4X71
|
||||||
|
eeJ+fOLgE2JlyqXRcGzKtEz5YzAFP74oC2vBAP9w0MrbRVtzwQPa4Omyy1SMtwoP
|
||||||
|
a2QmPB52aJ6nhfBlArg4BGIsozASCisGAQQBl1UBBQEBB0C+DsCLXf4vApdVZ71N
|
||||||
|
wjQUGQp9nd6zyMXXsl7oPfGvDQMBCAeIeAQYFggAIBYhBIkqg13mIq22arDfh8nO
|
||||||
|
p4wJbO8QBQJiLKMwAhsMAAoJEMnOp4wJbO8QrhMBAKcljw2BYS05IPev6kKdrlZ4
|
||||||
|
0H3l4So/GlaI/bkhyEdHAQDytHkdN4TK4QF/p6i/6+F0pClZJINm9aOlCksq3thv
|
||||||
|
AQ==
|
||||||
|
=qCbs
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
@ -0,0 +1,4 @@
|
|||||||
|
6E10217E3187069E057DF5ABE0262A773B824745
|
||||||
|
F1D6AA729DE5DDF5F94CEEE2D764341778B42777
|
||||||
|
4695F7B9F768D4CB395C788FA7DCCFCD6EBA487B
|
||||||
|
892A835DE622ADB66AB0DF87C9CEA78C096CEF10
|
@ -0,0 +1,2 @@
|
|||||||
|
6E10217E3187069E057DF5ABE0262A773B824745
|
||||||
|
4695F7B9F768D4CB395C788FA7DCCFCD6EBA487B
|
@ -0,0 +1,2 @@
|
|||||||
|
6E10217E3187069E057DF5ABE0262A773B824745
|
||||||
|
892A835DE622ADB66AB0DF87C9CEA78C096CEF10
|
Loading…
Reference in New Issue