Merge pull request #100 from privatevoid-net/pr-flake-update

`flake.lock`: Update
This commit is contained in:
hercules-ci[bot] 2024-05-17 13:35:51 +00:00 committed by GitHub
commit ead45cfb2f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
55 changed files with 531 additions and 3804 deletions

View file

@ -58,7 +58,7 @@ in
fallthrough
}
chaos "Private Void DNS" info@privatevoid.net
forward hyprspace. 127.80.1.53:5380
forward hyprspace. 127.43.104.80:11355
forward ${domain}. ${lib.concatStringsSep " " authoritativeServers} {
policy random
}

View file

@ -1,5 +0,0 @@
{ depot, ... }:
{
dns.records.vault.target = [ depot.hours.VEGAS.interfaces.primary.addrPublic ];
}

View file

@ -10,11 +10,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1707830867,
"narHash": "sha256-PAdwm5QqdlwIqGrfzzvzZubM+FXtilekQ/FA0cI49/o=",
"lastModified": 1715290355,
"narHash": "sha256-2T7CHTqBXJJ3ZC6R/4TXTcKoXWHcvubKNj9SfomURnw=",
"owner": "ryantm",
"repo": "agenix",
"rev": "8cb01a0e717311680e0cbca06a76cbceba6f3ed6",
"rev": "8d37c5bdeade12b6479c85acd133063ab53187a0",
"type": "github"
},
"original": {
@ -40,11 +40,11 @@
]
},
"locked": {
"lastModified": 1707922053,
"narHash": "sha256-wSZjK+rOXn+UQiP1NbdNn5/UW6UcBxjvlqr2wh++MbM=",
"lastModified": 1711742460,
"narHash": "sha256-0O4v6e4a1toxXZ2gf5INhg4WPE5C5T+SVvsBt+45Mcc=",
"owner": "zhaofengli",
"repo": "attic",
"rev": "6eabc3f02fae3683bffab483e614bebfcd476b21",
"rev": "4dbdbee45728d8ce5788db6461aaaa89d98081f0",
"type": "github"
},
"original": {
@ -121,11 +121,11 @@
]
},
"locked": {
"lastModified": 1705332421,
"narHash": "sha256-USpGLPme1IuqG78JNqSaRabilwkCyHmVWY0M9vYyqEA=",
"lastModified": 1713532798,
"narHash": "sha256-wtBhsdMJA3Wa32Wtm1eeo84GejtI43pMrFrmwLXrsEc=",
"owner": "numtide",
"repo": "devshell",
"rev": "83cb93d6d063ad290beee669f4badf9914cc16ec",
"rev": "12e914740a25ea1891ec619bb53cf5e6ca922e40",
"type": "github"
},
"original": {
@ -197,11 +197,11 @@
]
},
"locked": {
"lastModified": 1706830856,
"narHash": "sha256-a0NYyp+h9hlb7ddVz4LUn1vT/PLwqfrWYcHMvFB1xYg=",
"lastModified": 1715865404,
"narHash": "sha256-/GJvTdTpuDjNn84j82cU6bXztE0MSkdnTWClUCRub78=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "b253292d9c0a5ead9bc98c4e9a26c6312e27d69f",
"rev": "8dc45382d5206bd292f9c2768b8058a8fd8311d9",
"type": "github"
},
"original": {
@ -210,6 +210,42 @@
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": [
"nix-super",
"nixpkgs"
]
},
"locked": {
"lastModified": 1712014858,
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"haskell-flake": {
"locked": {
"lastModified": 1684780604,
@ -235,11 +271,11 @@
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1708547903,
"narHash": "sha256-7FXt8lznqCO8w3c0YFcq1slwueqEb73n/yeTai0gSpc=",
"lastModified": 1715869560,
"narHash": "sha256-X040hL0QF2uDhOqTrGIFqrpb9bTH/OOYLa34pjqT6NY=",
"owner": "hercules-ci",
"repo": "hercules-ci-agent",
"rev": "fa0a146c8711761606f01f06be7018696e419438",
"rev": "459c8a35a501f0d7d9d4a842505c61bd36b119e3",
"type": "github"
},
"original": {
@ -258,11 +294,11 @@
]
},
"locked": {
"lastModified": 1708547820,
"narHash": "sha256-xU/KC1PWqq5zL9dQ9wYhcdgxAwdeF/dJCLPH3PNZEBg=",
"lastModified": 1713898448,
"narHash": "sha256-6q6ojsp/Z9P2goqnxyfCSzFOD92T3Uobmj8oVAicUOs=",
"owner": "hercules-ci",
"repo": "hercules-ci-effects",
"rev": "0ca27bd58e4d5be3135a4bef66b582e57abe8f4a",
"rev": "c0302ec12d569532a6b6bd218f698bc402e93adc",
"type": "github"
},
"original": {
@ -292,6 +328,27 @@
"type": "github"
}
},
"hyprspace": {
"inputs": {
"flake-parts": [
"flake-parts"
],
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1715699972,
"narHash": "sha256-CNGszsuNwWSiUJqFGH2OeMCOpSrhaw7+logFZFenu68=",
"owner": "privatevoid-net",
"repo": "hyprspace",
"rev": "0c8f66c404c98f5cfd895ebe24e439e37409e80a",
"type": "github"
},
"original": {
"owner": "privatevoid-net",
"repo": "hyprspace",
"type": "github"
}
},
"libgit2": {
"flake": false,
"locked": {
@ -308,22 +365,6 @@
"type": "github"
}
},
"lowdown-src": {
"flake": false,
"locked": {
"lastModified": 1633514407,
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
"owner": "kristapsdz",
"repo": "lowdown",
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
"type": "github"
},
"original": {
"owner": "kristapsdz",
"repo": "lowdown",
"type": "github"
}
},
"mms": {
"inputs": {
"flake-compat": [
@ -379,11 +420,11 @@
},
"nix-filter": {
"locked": {
"lastModified": 1705332318,
"narHash": "sha256-kcw1yFeJe9N4PjQji9ZeX47jg0p9A0DuU4djKvg1a7I=",
"lastModified": 1710156097,
"narHash": "sha256-1Wvk8UP7PXdf8bCCaEoMnOT1qe5/Duqgj+rL8sRQsSM=",
"owner": "numtide",
"repo": "nix-filter",
"rev": "3449dc925982ad46246cfc36469baf66e1b64f17",
"rev": "3342559a24e85fc164b295c3444e8a139924675b",
"type": "github"
},
"original": {
@ -395,22 +436,23 @@
"nix-super": {
"inputs": {
"flake-compat": "flake-compat_2",
"flake-parts": "flake-parts_2",
"libgit2": "libgit2",
"lowdown-src": "lowdown-src",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-regression": [
"blank"
]
],
"pre-commit-hooks": "pre-commit-hooks"
},
"locked": {
"host": "git.privatevoid.net",
"lastModified": 1701958654,
"narHash": "sha256-ZhXujNwvwTDLmCpYb7h2bTDdZG4h97hEYjzBmKP8p2U=",
"lastModified": 1713821351,
"narHash": "sha256-JctHGT1oa4pet4PgUKRM7pf0w+qGe0a/ahVij8bee3o=",
"owner": "max",
"repo": "nix-super",
"rev": "661b025c79eac08beda593ede47b41b2052e8ebf",
"rev": "5ecd820c18b1aaa3c8ee257a7a9a2624c4107031",
"type": "gitlab"
},
"original": {
@ -422,11 +464,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1708296515,
"narHash": "sha256-FyF489fYNAUy7b6dkYV6rGPyzp+4tThhr80KNAaF/yY=",
"lastModified": 1715534503,
"narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b98a4e1746acceb92c509bc496ef3d0e5ad8d4aa",
"rev": "2057814051972fa1453ddfb0d98badbea9b83c06",
"type": "github"
},
"original": {
@ -438,11 +480,27 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1708541170,
"narHash": "sha256-WzeyGUHjvDlVWTw0q03O3WaQevZzjk7gRWQ6RdlCnE4=",
"lastModified": 1714076141,
"narHash": "sha256-Drmja/f5MRHZCskS6mvzFqxEaZMeciScCTFxWVLqWEY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e6d61b7214a8df4fa5a0e3d76506f12689585bab",
"rev": "7bb2ccd8cdc44c91edba16c48d2c8f331fb3d856",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1715886718,
"narHash": "sha256-1vHvNbkDx2+PIJoTzehdaFH8BLPTTIwUFkUL+MY53h0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5aab418b48c79823439d0f71b1e1a1c9300cd4fc",
"type": "github"
},
"original": {
@ -452,6 +510,38 @@
"type": "github"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": [
"nix-super"
],
"flake-utils": "flake-utils",
"gitignore": [
"nix-super"
],
"nixpkgs": [
"nix-super",
"nixpkgs"
],
"nixpkgs-stable": [
"nix-super",
"nixpkgs"
]
},
"locked": {
"lastModified": 1712897695,
"narHash": "sha256-nMirxrGteNAl9sWiOhoN5tIHyjBbVi5e2tgZUgZlK3Y=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "40e6053ecb65fcbf12863338a6dcefb3f55f1bf8",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"repin-flake-utils": {
"inputs": {
"systems": [
@ -459,11 +549,11 @@
]
},
"locked": {
"lastModified": 1705309234,
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
@ -482,11 +572,12 @@
"flake-parts": "flake-parts",
"hercules-ci-agent": "hercules-ci-agent",
"hercules-ci-effects": "hercules-ci-effects",
"hyprspace": "hyprspace",
"mms": "mms",
"nar-serve": "nar-serve",
"nix-filter": "nix-filter",
"nix-super": "nix-super",
"nixpkgs": "nixpkgs_2",
"nixpkgs": "nixpkgs_3",
"repin-flake-utils": "repin-flake-utils",
"systems": "systems_2"
}

View file

@ -36,6 +36,13 @@
};
};
hyprspace = {
url = "github:privatevoid-net/hyprspace";
inputs = {
flake-parts.follows = "flake-parts";
};
};
agenix = {
url = "github:ryantm/agenix";
inputs.nixpkgs.follows = "nixpkgs";

View file

@ -1,12 +0,0 @@
{ config, pkgs, depot, ... }:
{
services.vault = {
enable = true;
storageBackend = "file";
storagePath = "/srv/storage/private/vault";
extraConfig = "ui = true";
package = pkgs.vault-bin;
};
services.nginx.virtualHosts."vault.${depot.lib.meta.domain}" = depot.lib.nginx.vhosts.proxy "http://${config.services.vault.address}";
}

View file

@ -26,7 +26,6 @@
./services/minecraft
./services/reflex
./services/sso
./services/vault
./services/websites
./services/wireguard-server
depot.nixosModules.hyprspace

View file

@ -1,7 +1,7 @@
{ pkgs, depot, lib, config, ... }:
let
inherit (config.networking) hostName;
inherit (depot.packages) hyprspace;
hyprspace = depot.inputs.hyprspace.packages.default;
hyprspaceCapableNodes = lib.filterAttrs (_: host: host.hyprspace.enable) depot.hours;
peersFormatted = builtins.mapAttrs (name: x: {
inherit name;

View file

@ -19,7 +19,7 @@
};
keycloak = pkgs.callPackage ./keycloak-custom-jre.nix {
jre = self'.packages.jre17_standard;
inherit (self'.packages) keycloak;
};
patroni = pkgs.callPackage ./patroni.nix {

View file

@ -1,10 +1,10 @@
{ nixosTest, keycloak, jre }:
{ nixosTest, keycloak }:
nixosTest {
name = "keycloak";
nodes.machine.services.keycloak = {
enable = true;
package = keycloak.override { inherit jre; };
package = keycloak;
database.passwordFile = builtins.toFile "keycloak-test-password" "kcnixostest1234";
settings = {
proxy = "edge";

View file

@ -2,7 +2,7 @@
, tzdata, wire
, yarn, nodejs, python3, cacert
, jq, moreutils
, nix-update-script, nixosTests
, nix-update-script, nixosTests, xcbuild
}:
let
@ -18,38 +18,35 @@ let
done
rm -r packages/grafana-e2e
'';
# Injects a `t.Skip()` into a given test since
# there's apparently no other way to skip tests here.
skipTest = lineOffset: testCase: file:
let
jumpAndAppend = lib.concatStringsSep ";" (lib.replicate (lineOffset - 1) "n" ++ [ "a" ]);
in ''
sed -i -e '/${testCase}/{
${jumpAndAppend} t.Skip();
}' ${file}
'';
in
buildGoModule rec {
pname = "grafana";
version = "10.3.1";
version = "10.4.2";
excludedPackages = [ "alert_webhook_listener" "clean-swagger" "release_publisher" "slow_proxy" "slow_proxy_mac" "macaron" "devenv" "modowners" ];
subPackages = [ "pkg/cmd/grafana" "pkg/cmd/grafana-server" "pkg/cmd/grafana-cli" ];
src = fetchFromGitHub {
owner = "grafana";
repo = "grafana";
rev = "v${version}";
hash = "sha256-UPIq7BWTlT0omt/SM5+vkfOHvsdcx/ikkjcW9X8pcw0=";
hash = "sha256-ahG9ABJJUUgrFqqNjkJRA1Gia8T4J90jIsCMFOhZ55w=";
};
# borrowed from: https://github.com/NixOS/nixpkgs/blob/d70d9425f49f9aba3c49e2c389fe6d42bac8c5b0/pkgs/development/tools/analysis/snyk/default.nix#L20-L22
env = lib.optionalAttrs (stdenv.isDarwin && stdenv.isx86_64) {
# Fix error: no member named 'aligned_alloc' in the global namespace.
# Occurs while building @esfx/equatable@npm:1.0.2 on x86_64-darwin
NIX_CFLAGS_COMPILE = "-D_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION=1";
};
offlineCache = stdenv.mkDerivation {
name = "${pname}-${version}-yarn-offline-cache";
inherit src;
inherit src env;
nativeBuildInputs = [
yarn nodejs cacert
jq moreutils
];
jq moreutils python3
# @esfx/equatable@npm:1.0.2 fails to build on darwin as it requires `xcbuild`
] ++ lib.optionals stdenv.isDarwin [ xcbuild.xcbuild ];
postPatch = ''
${patchAwayGrafanaE2E}
'';
@ -58,7 +55,7 @@ buildGoModule rec {
export HOME="$(mktemp -d)"
yarn config set enableTelemetry 0
yarn config set cacheFolder $out
yarn config set --json supportedArchitectures.os '[ "linux" ]'
yarn config set --json supportedArchitectures.os '[ "linux", "darwin" ]'
yarn config set --json supportedArchitectures.cpu '["arm", "arm64", "ia32", "x64"]'
yarn
runHook postBuild
@ -67,14 +64,21 @@ buildGoModule rec {
dontInstall = true;
dontFixup = true;
outputHashMode = "recursive";
outputHash = "sha256-70eMa8E483f/Bz7iy+4Seap1EfIdjD5krnt6W9CUows=";
outputHash = rec {
x86_64-linux = "sha256-3CZgs732c6Z64t2sfWjPAmMFKVTzoolv2TwrbjeRCBA=";
aarch64-linux = x86_64-linux;
aarch64-darwin = "sha256-NKEajOe9uDZw0MF5leiKBIRH1CHUELRho7gyCa96BO8=";
x86_64-darwin = aarch64-darwin;
}.${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}");
};
disallowedRequisites = [ offlineCache ];
vendorHash = "sha256-Gf2A22d7/8xU/ld7kveqGonVKGFCArGNansPRGhfyXM=";
vendorHash = "sha256-XmIF/ZWVO1qjSmRPTFnHgxvnliXXicGgsV8gQcKJl9U=";
nativeBuildInputs = [ wire yarn jq moreutils removeReferencesTo python3 ];
proxyVendor = true;
nativeBuildInputs = [ wire yarn jq moreutils removeReferencesTo python3 ] ++ lib.optionals stdenv.isDarwin [ xcbuild.xcbuild ];
postPatch = ''
${patchAwayGrafanaE2E}
@ -89,36 +93,6 @@ buildGoModule rec {
GOARCH= CGO_ENABLED=0 go generate ./pkg/plugins/plugindef
GOARCH= CGO_ENABLED=0 go generate ./kinds/gen.go
GOARCH= CGO_ENABLED=0 go generate ./public/app/plugins/gen.go
GOARCH= CGO_ENABLED=0 go generate ./pkg/kindsys/report.go
# Work around `main module (github.com/grafana/grafana) does not contain package github.com/grafana/grafana/pkg/util/xorm`.
# Apparently these files confuse the dependency resolution for the go builder implemented here.
rm pkg/util/xorm/go.{mod,sum}
# The testcase makes an API call against grafana.com:
#
# [...]
# grafana> t=2021-12-02T14:24:58+0000 lvl=dbug msg="Failed to get latest.json repo from github.com" logger=update.checker error="Get \"https://raw.githubusercontent.com/grafana/grafana/main/latest.json\": dial tcp: lookup raw.githubusercontent.com on [::1]:53: read udp [::1]:36391->[::1]:53: read: connection refused"
# grafana> t=2021-12-02T14:24:58+0000 lvl=dbug msg="Failed to get plugins repo from grafana.com" logger=plugin.manager error="Get \"https://grafana.com/api/plugins/versioncheck?slugIn=&grafanaVersion=\": dial tcp: lookup grafana.com on [::1]:53: read udp [::1]:41796->[::1]:53: read: connection refused"
${skipTest 1 "Request is not forbidden if from an admin" "pkg/tests/api/plugins/api_plugins_test.go"}
# Skip a flaky test (https://github.com/NixOS/nixpkgs/pull/126928#issuecomment-861424128)
${skipTest 2 "it should change folder successfully and return correct result" "pkg/services/libraryelements/libraryelements_patch_test.go"}
# Skip flaky tests (https://logs.ofborg.org/?key=nixos/nixpkgs.263185&attempt_id=5b056a17-67a7-4b74-9dc7-888eb1d6c2dd)
${skipTest 1 "TestIntegrationRulerAccess" "pkg/tests/api/alerting/api_alertmanager_test.go"}
${skipTest 1 "TestIntegrationRulePause" "pkg/tests/api/alerting/api_ruler_test.go"}
# main module (github.com/grafana/grafana) does not contain package github.com/grafana/grafana/scripts/go
rm -r scripts/go
# Requires making API calls against storage.googleapis.com:
#
# [...]
# grafana> 2023/08/24 08:30:23 failed to copy objects, err: Post "https://storage.googleapis.com/upload/storage/v1/b/grafana-testing-repo/o?alt=json&name=test-path%2Fbuild%2FTestCopyLocalDir2194093976%2F001%2Ffile2.txt&prettyPrint=false&projection=full&uploadType=multipart": dial tcp: lookup storage.googleapis.com on [::1]:53: read udp [::1]:36436->[::1]:53: read: connection refused
# grafana> panic: test timed out after 10m0s
rm pkg/build/gcloud/storage/gsutil_test.go
# Setup node_modules
export HOME="$(mktemp -d)"
@ -175,10 +149,10 @@ buildGoModule rec {
meta = with lib; {
description = "Gorgeous metric viz, dashboards & editors for Graphite, InfluxDB & OpenTSDB";
license = licenses.agpl3;
license = licenses.agpl3Only;
homepage = "https://grafana.com";
maintainers = with maintainers; [ offline fpletz willibutz globin ma27 Frostman ];
platforms = platforms.linux ++ platforms.darwin;
platforms = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];
mainProgram = "grafana-server";
};
}

View file

@ -1,2 +0,0 @@
source ../../build-support/activate-shell
nix_direnv_watch_file project.nix

View file

@ -1,2 +0,0 @@
/hyprspace.png
/hyprspace

View file

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1,209 +0,0 @@
<img src="https://cdn.privatevoid.net/assets/ba/f010319e49e26c15063df091b495396442f5f3d4463093b86ed400569f5473" width="250">
# Hyprspace
[![Go Report Card](https://goreportcard.com/badge/github.com/hyprspace/hyprspace)](https://goreportcard.com/report/github.com/hyprspace/hyprspace)
[![](https://img.shields.io/matrix/hyprspace:matrix.org)](https://matrix.to/#/%23hyprspace:matrix.org)
A Lightweight VPN Built on top of IPFS & Libp2p for Truly Distributed Networks.
https://user-images.githubusercontent.com/19558067/152407636-a5f4ae1f-9493-4346-bf73-0de109928415.mp4
## Table of Contents
- [A Bit of Backstory](#a-bit-of-backstory)
- [Use Cases](#use-cases)
- [A Digital Nomad](#a-digital-nomad)
- [A Privacy Advocate](#a-privacy-advocate)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Usage](#usage)
- [Commands](#commands)
- [Tutorial](#tutorial)
## A Bit of Backstory
[Libp2p](https://libp2p.io) is a networking library created by [Protocol Labs](https://protocol.ai) that allows nodes to discover each other using a Distributed Hash Table. Paired with [NAT hole punching](https://en.wikipedia.org/wiki/Hole_punching_(networking)) this allows Hyprspace to create a direct encrypted tunnel between two nodes even if they're both behind firewalls.
**Moreover! Each node doesn't even need to know the other's ip address prior to starting up the connection.** This makes Hyprspace perfect for devices that frequently migrate between locations but still require a constant virtual ip address.
### So How Does Hyprspace Compare to Something Like Wireguard?
[WireGuard](https://wireguard.com) is an amazing VPN written by Jason A. Donenfeld. If you haven't already, definitely go check it out! WireGuard actually inspired me to write Hyprspace. That said, although WireGuard is in a class of its own as a great VPN, it requires at least one of your nodes to have a public IP address. In this mode, as long as one of your nodes is publicly accessible, it can be used as a central relay to reach the other nodes in the network. However, this means that all of the traffic for your entire system is going through that one system which can slow down your network and make it fragile in the case that node goes down and you lose the whole network. So instead say that you want each node to be able to directly connect to each other as they do in Hyprspace. Unfortunately through WireGuard this would require every node to be publicly addressable which means manual port forwarding and no travelling nodes.
By contrast Hyprspace allows all of your nodes to connect directly to each other creating a strong reliable network even if they're all behind their own NATs/firewalls. No manual port forwarding required!
## Use Cases:
##### A Digital Nomad
I use this system when travelling, if I'm staying in a rental or hotel and want to try something out on a Raspberry Pi I can plug the Pi into the location's router or ethernet port and then just ssh into the system using the same-old internal Hyprspace ip address without having to worry about their NAT or local firewall. Furthermore, if I'm connected to the Virtual Hyprspace Network I can ssh into my machines at home without requiring me to set up any sort of port forwarding.
##### A Privacy Advocate
Honestly, I even use this system when I'm at home and could connect directly to my local infrastructure. Using Hyprspace however, I don't have to trust the security of my local network and Hyprspace will intelligently connect to my machines using their local ip addresses for maximum speed.
If anyone else has some use cases please add them! Pull requests welcome!
| :exclamation: | Hyprspace is still a very new project. Although we've tested the code locally for security, it hasn't been audited by a third party yet. We probably wouldn't trust it yet in high security environments. |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
## Getting Started
### Prerequisites
If you're running Hyprspace on Windows you'll need to install [tap-windows](http://build.openvpn.net/downloads/releases/).
### Installation
#### Automatic (Linux & MacOS)
```
curl -L https://hyprspace.io/install.sh | bash
```
#### Manual
1. Go to Hyprspace Releases (over there -->)
2. Copy the link for your corresponding OS and Architecture.
3. Run `sudo mkdir -p /usr/local/bin/`
4. Run `sudo curl -L "PATH-TO-RELEASE" -o /usr/local/bin/hyprspace`
5. Run `sudo chmod a+x /usr/local/bin/hyprspace`
6. (Optional) Run `sudo ln -s /usr/local/bin/hyprspace /usr/bin/hyprspace`
## Usage
### Commands
| Command | Alias | Description |
| ------------------- | ------- | -------------------------------------------------------------------------- |
| `help` | `?` | Get help with a specific subcommand. |
| `init` | `i` | Initialize an interface's configuration. |
| `up` | `up` | Create and Bring Up a Hyprspace Interface |
| `down ` | `d` | Bring Down and Delete A Hyprspace Interface |
### Global Flags
| Flag | Alias | Description |
| ------------------- | ------- | -------------------------------------------------------------------------- |
| `--config` | `-c` | Specify the path to a hyprspace config for an interface. |
## Tutorial
### Initializing an Interface
The first thing we'll want to do once we've got Hyprspace installed is
initialize the configuration for an interface. In this case we'll call the
interface on our local machine `hs0` (for hypr-space 0) and `hs1` on our remote server
but yours could be anything you'd like.
(Note: if you're using a Mac you'll have to use the interface name `utun[0-9]`. Check which interfaces are already in use by running `ip a` once you've got `iproute2mac` installed.)
(Note: if you're using Windows you'll have to use the interface name as seen in Control Panel. IP address will be set automatically only if you run Hyprspace as Administrator.)
###### Local Machine
```bash
sudo hyprspace init hs0
```
###### Remote Machine
```bash
sudo hyprspace init hs1
```
### Add Each Machine As A Peer Of The Other
Now that we've got a set of configurations we'll want to
tell the machines about each other. By default Hyprspace will
put the interface configurations in `/etc/hyprspace/interface-name.json`.
So for our example we'll run
###### Local Machine
```bash
sudo nano /etc/hyprspace/hs0.json
```
and
###### Remote Machine
```bash
sudo nano /etc/hyprspace/hs1.json
```
### Update Peer Configs
Now in each config we'll add the other machine's ID as a peer.
You can find each machine's ID at the top of their configuration file.
Update,
```json
{
"peers": {}
}
```
to
```json
{
"peers": {
"10.1.1.2": {
"id": "YOUR-OTHER-PEER-ID"
}
}
}
```
Notice here we'll have to pick one of our machines to be `10.1.1.1`
and the other to be `10.1.1.2`. Make sure to update the interface's IP
address for the machine who needs to change to be `10.1.1.2`.
### Starting Up the Interfaces!
Now that we've got our configs all sorted we can start up the two interfaces!
###### Local Machine
```bash
sudo hyprspace up hs0
```
and
###### Remote Machine
```bash
sudo hyprspace up hs1
```
After a few seconds you should see a the network finish setting up
and find your other machine. We can now test the connection by
pinging back and forth across the network.
###### Local Machine
```bash
ping 10.1.1.2
```
### Stopping the Interface and Cleaning Up
Now to stop the interface and clean up the system you can run,
###### Local Machine
```bash
sudo hyprspace down hs0
```
and,
###### Remote Machine
```bash
sudo hyprspace down hs1
```
## Disclaimer & Copyright
WireGuard is a registered trademark of Jason A. Donenfeld.
## License
Copyright 2021-2022 Alec Scott <hi@alecbcs.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1,81 +0,0 @@
package cli
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"github.com/DataDrake/cli-ng/v2/cmd"
"github.com/hyprspace/hyprspace/config"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multibase"
)
// Init creates a configuration for a Hyprspace Interface.
var Init = cmd.Sub{
Name: "init",
Alias: "i",
Short: "Initialize An Interface Config",
Run: InitRun,
}
// InitRun handles the execution of the init command.
func InitRun(r *cmd.Root, c *cmd.Sub) {
ifName := r.Flags.(*GlobalFlags).InterfaceName
if ifName == "" {
ifName = "hyprspace"
}
configPath := r.Flags.(*GlobalFlags).Config
if configPath == "" {
configPath = "/etc/hyprspace/" + ifName + ".json"
}
privKey, _, err := crypto.GenerateKeyPair(crypto.Ed25519, 256)
checkErr(err)
keyBytes, err := crypto.MarshalPrivateKey(privKey)
checkErr(err)
// Setup an initial default command.
new := config.Config{
EncodedPrivateKey: multibase.MustNewEncoder(multibase.Base58BTC).Encode(keyBytes),
EncodedListenAddresses: []string{
"/ip4/0.0.0.0/tcp/8001",
"/ip4/0.0.0.0/udp/8001/quic-v1",
"/ip6/::/tcp/8001",
"/ip6/::/udp/8001/quic-v1",
},
Peers: make([]config.Peer, 0),
}
out, err := json.MarshalIndent(&new, "", " ")
checkErr(err)
err = os.MkdirAll(filepath.Dir(configPath), os.ModePerm)
checkErr(err)
f, err := os.Create(configPath)
checkErr(err)
_, err = f.Write(out)
checkErr(err)
err = f.Close()
checkErr(err)
fmt.Printf("Initialized new config at %s\n", configPath)
peerId, err := peer.IDFromPrivateKey(privKey)
if err == nil {
fmt.Println("Add this entry to your other peers:")
fmt.Println("{")
hostname, err := os.Hostname()
if err == nil {
fmt.Printf(" \"name\": \"%s\",\n", hostname)
}
fmt.Printf(" \"id\": \"%s\"\n", peerId)
fmt.Println("}")
}
}

View file

@ -1,26 +0,0 @@
package cli
import (
"fmt"
"github.com/DataDrake/cli-ng/v2/cmd"
"github.com/hyprspace/hyprspace/rpc"
)
var Peers = cmd.Sub{
Name: "peers",
Short: "List peer connections",
Run: PeersRun,
}
func PeersRun(r *cmd.Root, c *cmd.Sub) {
ifName := r.Flags.(*GlobalFlags).InterfaceName
if ifName == "" {
ifName = "hyprspace"
}
peers := rpc.Peers(ifName)
for _, ma := range peers.PeerAddrs {
fmt.Println(ma)
}
}

View file

@ -1,65 +0,0 @@
package cli
import (
"fmt"
"log"
"sync"
"time"
"github.com/DataDrake/cli-ng/v2/cmd"
)
var appVersion string = "develop"
// GlobalFlags contains the flags for commands.
type GlobalFlags struct {
Config string `short:"c" long:"config" desc:"Specify a custom config path."`
InterfaceName string `short:"i" long:"interface" desc:"Interface name."`
}
// Root is the main command.
var Root *cmd.Root
func init() {
Root = &cmd.Root{
Name: "hyprspace",
Short: "Hyprspace Distributed Network",
Version: appVersion,
Flags: &GlobalFlags{},
}
cmd.Register(&cmd.Help)
cmd.Register(&Init)
cmd.Register(&Up)
cmd.Register(&Status)
cmd.Register(&Peers)
cmd.Register(&Route)
cmd.Register(&cmd.Version)
}
func checkErr(err error) {
if err != nil {
log.Fatal(err)
}
}
// Spinner is an array of the progression of the spinner.
var Spinner = []string{"|", "/", "-", "\\"}
// SpinnerWait displays the actual spinner
func SpinnerWait(done chan int, message string, wg *sync.WaitGroup) {
ticker := time.NewTicker(time.Millisecond * 128)
frameCounter := 0
for {
select {
case <-done:
wg.Done()
return
default:
<-ticker.C
ind := frameCounter % len(Spinner)
fmt.Printf("\r[%v] "+message, Spinner[ind])
frameCounter++
}
}
}

View file

@ -1,53 +0,0 @@
package cli
import (
"fmt"
"github.com/DataDrake/cli-ng/v2/cmd"
"github.com/hyprspace/hyprspace/rpc"
)
var Route = cmd.Sub{
Name: "route",
Alias: "r",
Short: "Control routing",
Args: &RouteArgs{},
Run: RouteRun,
}
type RouteArgs struct {
Action string
Args []string `zero:"true"`
}
func RouteRun(r *cmd.Root, c *cmd.Sub) {
// Parse Command Args
args := c.Args.(*RouteArgs)
ifName := r.Flags.(*GlobalFlags).InterfaceName
if ifName == "" {
ifName = "hyprspace"
}
action := rpc.RouteAction(args.Action)
rArgs := rpc.RouteArgs{
Action: action,
Args: args.Args,
}
reply := rpc.Route(ifName, rArgs)
for _, r := range reply.Routes {
var target string
connectStatus := ""
if r.IsRelay {
target = fmt.Sprintf("/p2p/%s/p2p-circuit/p2p/%s", r.RelayAddr, r.TargetAddr)
} else {
target = fmt.Sprintf("/p2p/%s", r.TargetAddr)
}
if r.TargetName != "" {
target = fmt.Sprintf("@%s %s", r.TargetName, target)
}
if r.IsConnected {
connectStatus = " connected"
}
fmt.Printf("%s via %s%s\n", &r.Network, target, connectStatus)
}
}

View file

@ -1,30 +0,0 @@
package cli
import (
"fmt"
"github.com/DataDrake/cli-ng/v2/cmd"
"github.com/hyprspace/hyprspace/rpc"
)
var Status = cmd.Sub{
Name: "status",
Alias: "s",
Short: "Display Hyprspace daemon status",
Run: StatusRun,
}
func StatusRun(r *cmd.Root, c *cmd.Sub) {
ifName := r.Flags.(*GlobalFlags).InterfaceName
if ifName == "" {
ifName = "hyprspace"
}
status := rpc.Status(ifName)
fmt.Println("PeerID:", status.PeerID)
fmt.Println("Swarm peers:", status.SwarmPeersCurrent)
fmt.Printf("Connected VPN nodes: %d/%d\n", status.NetPeersCurrent, status.NetPeersMax)
printList(status.NetPeerAddrsCurrent)
fmt.Println("Addresses:")
printList(status.ListenAddrs)
}

View file

@ -1,357 +0,0 @@
package cli
import (
"context"
"encoding/binary"
"errors"
"fmt"
"io/fs"
"net"
"net/http"
"os"
"os/signal"
"path/filepath"
"sync"
"syscall"
"time"
"github.com/DataDrake/cli-ng/v2/cmd"
"github.com/hyprspace/hyprspace/config"
hsdns "github.com/hyprspace/hyprspace/dns"
"github.com/hyprspace/hyprspace/p2p"
hsrpc "github.com/hyprspace/hyprspace/rpc"
"github.com/hyprspace/hyprspace/tun"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/yl2chen/cidranger"
)
type MuxStream struct {
Stream *network.Stream
Lock *sync.Mutex
}
var (
cfg *config.Config
node host.Host
// iface is the tun device used to pass packets between
// Hyprspace and the user's machine.
tunDev *tun.TUN
// activeStreams is a map of active streams to a peer
activeStreams map[peer.ID]MuxStream
// context
ctx context.Context
// context cancel function
ctxCancel func()
)
// Up creates and brings up a Hyprspace Interface.
var Up = cmd.Sub{
Name: "up",
Alias: "up",
Short: "Create and Bring Up a Hyprspace Interface.",
Run: UpRun,
}
// UpRun handles the execution of the up command.
func UpRun(r *cmd.Root, c *cmd.Sub) {
ifName := r.Flags.(*GlobalFlags).InterfaceName
if ifName == "" {
ifName = "hyprspace"
}
// Parse Global Config Flag for Custom Config Path
configPath := r.Flags.(*GlobalFlags).Config
if configPath == "" {
configPath = "/etc/hyprspace/" + ifName + ".json"
}
// Read in configuration from file.
cfg2, err := config.Read(configPath)
checkErr(err)
cfg2.Interface = ifName
cfg = cfg2
fmt.Println("[+] Creating TUN Device")
// Create new TUN device
tunDev, err = tun.New(
cfg.Interface,
tun.Address(cfg.BuiltinAddr.String()+"/32"),
tun.MTU(1420),
)
if err != nil {
checkErr(err)
}
allRoutes, err := cfg.PeerLookup.ByRoute.CoveredNetworks(*cidranger.AllIPv4)
if err != nil {
checkErr(err)
}
var routeOpts []tun.Option
for _, r := range allRoutes {
routeOpts = append(routeOpts, tun.Route(r.Network()))
}
// Setup System Context
ctx, ctxCancel = context.WithCancel(context.Background())
fmt.Println("[+] Creating LibP2P Node")
// Create P2P Node
host, dht, err := p2p.CreateNode(
ctx,
cfg.PrivateKey,
cfg.ListenAddresses,
streamHandler,
p2p.NewClosedCircuitRelayFilter(cfg.Peers),
p2p.NewRecursionGater(cfg),
cfg.Peers,
)
checkErr(err)
host.SetStreamHandler(p2p.PeXProtocol, p2p.NewPeXStreamHandler(host, cfg))
node = host
for _, p := range cfg.Peers {
host.ConnManager().Protect(p.ID, "/hyprspace/peer")
}
fmt.Println("[+] Setting Up Node Discovery via DHT")
// Setup P2P Discovery
go p2p.Discover(ctx, host, dht, cfg.Peers)
// Configure path for lock
lockPath := filepath.Join(filepath.Dir(cfg.Path), cfg.Interface+".lock")
// PeX
go p2p.PeXService(ctx, host, cfg)
// Route metrics and latency
go p2p.RouteMetricsService(ctx, host, cfg)
// Register the application to listen for signals
go signalHandler(ctx, host, lockPath, dht)
// Log about various events
go eventLogger(ctx, host)
// RPC server
go hsrpc.RpcServer(ctx, multiaddr.StringCast(fmt.Sprintf("/unix/run/hyprspace-rpc.%s.sock", cfg.Interface)), host, *cfg, *tunDev)
// Magic DNS server
go hsdns.MagicDnsServer(ctx, *cfg, node)
// metrics endpoint
metricsPort, ok := os.LookupEnv("HYPRSPACE_METRICS_PORT")
if ok {
metricsTuple := fmt.Sprintf("127.0.0.1:%s", metricsPort)
http.Handle("/metrics", promhttp.Handler())
go func() {
http.ListenAndServe(metricsTuple, nil)
}()
fmt.Printf("[+] Listening for metrics scrape requests on http://%s/metrics\n", metricsTuple)
}
// Write lock to filesystem to indicate an existing running daemon.
err = os.WriteFile(lockPath, []byte(fmt.Sprint(os.Getpid())), os.ModePerm)
checkErr(err)
// Bring Up TUN Device
err = tunDev.Up()
if err != nil {
checkErr(errors.New("unable to bring up tun device"))
}
checkErr(tunDev.Apply(routeOpts...))
fmt.Println("[+] Network setup complete")
// + ----------------------------------------+
// | Listen For New Packets on TUN Interface |
// + ----------------------------------------+
// Initialize active streams map and packet byte array.
activeStreams = make(map[peer.ID]MuxStream)
for {
var packet = make([]byte, 1420)
// Read in a packet from the tun device.
plen, err := tunDev.Iface.Read(packet)
if errors.Is(err, fs.ErrClosed) {
fmt.Println("[-] Interface closed")
<-ctx.Done()
time.Sleep(1 * time.Second)
return
} else if err != nil {
fmt.Println(err)
continue
}
dstIP := net.IPv4(packet[16], packet[17], packet[18], packet[19])
if cfg.BuiltinAddr.Equal(dstIP) {
continue
}
var dst peer.ID
// Check route table for destination address.
route, found := cfg.FindRouteForIP(dstIP)
if found {
dst = route.Target.ID
go sendPacket(dst, packet, plen)
}
}
}
func sendPacket(dst peer.ID, packet []byte, plen int) {
// Check if we already have an open connection to the destination peer.
ms, ok := activeStreams[dst]
if ok {
if func() bool {
ms.Lock.Lock()
defer ms.Lock.Unlock()
// Write out the packet's length to the libp2p stream to ensure
// we know the full size of the packet at the other end.
err := binary.Write(*ms.Stream, binary.LittleEndian, uint16(plen))
if err == nil {
// Write the packet out to the libp2p stream.
// If everyting succeeds continue on to the next packet.
_, err = (*ms.Stream).Write(packet[:plen])
if err == nil {
(*ms.Stream).SetWriteDeadline(time.Now().Add(25 * time.Second))
return true
}
}
// If we encounter an error when writing to a stream we should
// close that stream and delete it from the active stream map.
(*ms.Stream).Close()
delete(activeStreams, dst)
return false
}() {
return
}
}
stream, err := node.NewStream(ctx, dst, p2p.Protocol)
if err != nil {
fmt.Println("[!] Failed to open stream to " + dst.String() + ": " + err.Error())
go p2p.Rediscover()
return
}
stream.SetWriteDeadline(time.Now().Add(25 * time.Second))
// Write packet length
err = binary.Write(stream, binary.LittleEndian, uint16(plen))
if err != nil {
stream.Close()
return
}
// Write the packet
_, err = stream.Write(packet[:plen])
if err != nil {
stream.Close()
return
}
// If all succeeds when writing the packet to the stream
// we should reuse this stream by adding it active streams map.
activeStreams[dst] = MuxStream{
Stream: &stream,
Lock: &sync.Mutex{},
}
}
func signalHandler(ctx context.Context, host host.Host, lockPath string, dht *dht.IpfsDHT) {
exitCh := make(chan os.Signal, 1)
rebootstrapCh := make(chan os.Signal, 1)
signal.Notify(exitCh, syscall.SIGINT, syscall.SIGTERM)
signal.Notify(rebootstrapCh, syscall.SIGUSR1)
for {
select {
case <-ctx.Done():
return
case <-rebootstrapCh:
fmt.Println("[-] Rebootstrapping on SIGUSR1")
host.ConnManager().TrimOpenConns(context.Background())
<-dht.ForceRefresh()
p2p.Rediscover()
case <-exitCh:
// Shut the node down
err := host.Close()
checkErr(err)
// Remove daemon lock from file system.
err = os.Remove(lockPath)
checkErr(err)
fmt.Println("Received signal, shutting down...")
tunDev.Iface.Close()
tunDev.Down()
ctxCancel()
}
}
}
func eventLogger(ctx context.Context, host host.Host) {
subCon, err := host.EventBus().Subscribe(new(event.EvtPeerConnectednessChanged))
checkErr(err)
for {
select {
case <-ctx.Done():
return
case ev := <-subCon.Out():
evt := ev.(event.EvtPeerConnectednessChanged)
for _, vpnPeer := range cfg.Peers {
if vpnPeer.ID == evt.Peer {
if evt.Connectedness == network.Connected {
for _, c := range host.Network().ConnsToPeer(evt.Peer) {
fmt.Printf("[+] Connected to %s/p2p/%s\n", c.RemoteMultiaddr().String(), evt.Peer.String())
}
} else if evt.Connectedness == network.NotConnected {
fmt.Printf("[!] Disconnected from %s\n", evt.Peer.String())
}
break
}
}
}
}
}
func streamHandler(stream network.Stream) {
// If the remote node ID isn't in the list of known nodes don't respond.
if _, ok := config.FindPeer(cfg.Peers, stream.Conn().RemotePeer()); !ok {
stream.Reset()
return
}
var packet = make([]byte, 1420)
var packetSize = make([]byte, 2)
for {
// Read the incoming packet's size as a binary value.
_, err := stream.Read(packetSize)
if err != nil {
stream.Close()
return
}
// Decode the incoming packet's size from binary.
size := binary.LittleEndian.Uint16(packetSize)
// Read in the packet until completion.
var plen uint16 = 0
for plen < size {
tmp, err := stream.Read(packet[plen:size])
plen += uint16(tmp)
if err != nil {
stream.Close()
return
}
}
stream.SetWriteDeadline(time.Now().Add(25 * time.Second))
tunDev.Iface.Write(packet[:size])
}
}

View file

@ -1,9 +0,0 @@
package cli
import "fmt"
func printList(strings []string) {
for _, ma := range strings {
fmt.Printf(" %s\n", ma)
}
}

View file

@ -1,220 +0,0 @@
package config
import (
"encoding/json"
"fmt"
"log"
"net"
"os"
"strings"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
"github.com/multiformats/go-multibase"
"github.com/yl2chen/cidranger"
)
// Config is the main Configuration Struct for Hyprspace.
type Config struct {
Path string `json:"-"`
Interface string `json:"-"`
EncodedListenAddresses []string `json:"listenAddresses"`
ListenAddresses []multiaddr.Multiaddr `json:"-"`
Peers []Peer `json:"peers"`
PeerLookup PeerLookup `json:"-"`
EncodedPrivateKey string `json:"privateKey"`
PrivateKey crypto.PrivKey `json:"-"`
BuiltinAddr net.IP `json:"-"`
}
// Peer defines a peer in the configuration. We might add more to this later.
type Peer struct {
ID peer.ID `json:"id"`
Name string `json:"name"`
BuiltinAddr net.IP `json:"-"`
Routes []Route `json:"routes"`
}
type Route struct {
NetworkStr string `json:"net"`
Network net.IPNet `json:"-"`
}
// PeerLookup is a helper struct for quickly looking up a peer based on various parameters
type PeerLookup struct {
ByRoute cidranger.Ranger
ByName map[string]Peer
}
type RouteTableEntry struct {
Net net.IPNet
Target Peer
}
func (rte RouteTableEntry) Network() net.IPNet {
return rte.Net
}
// Read initializes a config from a file.
func Read(path string) (*Config, error) {
in, err := os.ReadFile(path)
if err != nil {
return nil, err
}
result := Config{
EncodedListenAddresses: []string{
"/ip4/0.0.0.0/tcp/8001",
"/ip4/0.0.0.0/udp/8001/quic-v1",
"/ip6/::/tcp/8001",
"/ip6/::/udp/8001/quic-v1",
},
}
// Read in config settings from file.
err = json.Unmarshal(in, &result)
if err != nil {
return nil, err
}
_, keyBytes, err := multibase.Decode(result.EncodedPrivateKey)
if err != nil {
return nil, err
}
pk, err := crypto.UnmarshalPrivateKey(keyBytes)
if err != nil {
return nil, err
}
result.PrivateKey = pk
if err != nil {
return nil, err
}
peerID, err := peer.IDFromPrivateKey(result.PrivateKey)
if err != nil {
return nil, err
}
result.BuiltinAddr = mkBuiltinAddr(peerID)
for _, addrString := range result.EncodedListenAddresses {
addr, err := multiaddr.NewMultiaddr(addrString)
if err != nil {
return nil, err
}
result.ListenAddresses = append(result.ListenAddresses, addr)
}
result.PeerLookup.ByRoute = cidranger.NewPCTrieRanger()
result.PeerLookup.ByName = make(map[string]Peer)
for i, p := range result.Peers {
p.BuiltinAddr = mkBuiltinAddr(p.ID)
p.Routes = append(p.Routes, Route{
Network: net.IPNet{
IP: p.BuiltinAddr,
Mask: net.IPv4Mask(255, 255, 255, 255),
},
})
for _, r := range p.Routes {
if r.NetworkStr != "" {
_, n, err := net.ParseCIDR(r.NetworkStr)
if err != nil {
log.Fatal("[!] Invalid network:", r.NetworkStr)
}
r.Network = *n
}
result.PeerLookup.ByRoute.Insert(&RouteTableEntry{
Net: r.Network,
Target: p,
})
fmt.Printf("[+] Route %s via /p2p/%s\n", r.Network.String(), p.ID)
}
if p.Name != "" {
result.PeerLookup.ByName[strings.ToLower(p.Name)] = p
}
result.Peers[i] = p
}
// Overwrite path of config to input.
result.Path = path
return &result, nil
}
func mkBuiltinAddr(p peer.ID) net.IP {
builtinAddr := []byte{100, 64, 1, 2}
for i, b := range []byte(p) {
builtinAddr[(i%2)+2] ^= b
}
return net.IP(builtinAddr)
}
func FindPeer(peers []Peer, needle peer.ID) (*Peer, bool) {
for _, p := range peers {
if p.ID == needle {
return &p, true
}
}
return nil, false
}
func FindPeerByName(peers []Peer, needle string) (*Peer, bool) {
for _, p := range peers {
if p.Name == needle {
return &p, true
}
}
return nil, false
}
func FindPeerByIDPrefix(peers []Peer, needle string) (*Peer, bool) {
for _, p := range peers {
if strings.HasPrefix(p.ID.String(), needle) {
return &p, true
}
}
return nil, false
}
func FindPeerByCLIRef(peers []Peer, needle string) (*Peer, bool) {
if strings.HasPrefix(needle, "@") {
name := strings.TrimPrefix(needle, "@")
return FindPeerByName(peers, name)
} else {
return FindPeerByIDPrefix(peers, needle)
}
}
func (cfg Config) FindRoute(needle net.IPNet) (*RouteTableEntry, bool) {
networks, err := cfg.PeerLookup.ByRoute.CoveredNetworks(needle)
if err != nil {
fmt.Println(err)
return nil, false
} else if len(networks) == 0 {
return nil, false
} else if len(networks) > 1 {
for _, n := range networks {
fmt.Printf("[!] Found duplicate route %s to /p2p/%s for %s\n", n.Network(), n.(RouteTableEntry).Target.ID, needle)
}
}
return networks[0].(*RouteTableEntry), true
}
func (cfg Config) FindRouteForIP(needle net.IP) (*RouteTableEntry, bool) {
networks, err := cfg.PeerLookup.ByRoute.ContainingNetworks(needle)
if err != nil {
fmt.Println(err)
return nil, false
} else if len(networks) == 0 {
return nil, false
} else if len(networks) > 1 {
for _, n := range networks {
fmt.Printf("[!] Found duplicate route %s to /p2p/%s for %s\n", n.Network(), n.(RouteTableEntry).Target.ID, needle)
}
}
return networks[0].(*RouteTableEntry), true
}

View file

@ -1,159 +0,0 @@
package dns
import (
"context"
"fmt"
"net"
"os"
"strings"
"syscall"
"github.com/hyprspace/hyprspace/config"
"github.com/iguanesolutions/go-systemd/v5/resolved"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/miekg/dns"
"github.com/multiformats/go-multibase"
"github.com/vishvananda/netlink"
)
var domainSuffix = "hyprspace."
func mkAliasRecord(alias string, p peer.ID) *dns.CNAME {
cid, _ := peer.ToCid(p).StringOfBase(multibase.Base36)
return &dns.CNAME{
Hdr: dns.RR_Header{
Name: fmt.Sprintf("%s.%s", alias, domainSuffix),
Rrtype: dns.TypeCNAME,
Class: dns.ClassINET,
Ttl: 0,
},
Target: fmt.Sprintf("%s.%s", cid, domainSuffix),
}
}
func mkIDRecord(p peer.ID, addr net.IP) *dns.A {
cid, _ := peer.ToCid(p).StringOfBase(multibase.Base36)
return &dns.A{
Hdr: dns.RR_Header{
Name: fmt.Sprintf("%s.%s", cid, domainSuffix),
Rrtype: dns.TypeA,
Class: dns.ClassINET,
Ttl: 86400,
},
A: addr.To4(),
}
}
func writeResponse(msg *dns.Msg, q dns.Question, p peer.ID, addr net.IP) {
msg.Answer = append(msg.Answer, &dns.A{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeA,
Class: dns.ClassINET,
Ttl: 0,
},
A: addr.To4(),
})
cid, _ := peer.ToCid(p).StringOfBase(multibase.Base36)
msg.Extra = append(msg.Extra, &dns.TXT{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: 0,
},
Txt: []string{p.String(), cid},
})
}
func MagicDnsServer(ctx context.Context, config config.Config, node host.Host) {
dns.HandleFunc(domainSuffix, func(w dns.ResponseWriter, r *dns.Msg) {
m := new(dns.Msg)
m.SetReply(r)
for _, q := range r.Question {
switch q.Qtype {
case dns.TypeA:
if qpeer, err := peer.Decode(strings.TrimSuffix(q.Name, "."+domainSuffix)); err == nil {
if qpeer == node.ID() {
m.Answer = append(m.Answer, mkIDRecord(node.ID(), config.BuiltinAddr))
} else {
for _, p := range config.Peers {
if p.ID == qpeer {
m.Answer = append(m.Answer, mkIDRecord(p.ID, p.BuiltinAddr))
break
}
}
}
} else {
hostname, err := os.Hostname()
if err != nil {
fmt.Println("[!] [dns] " + err.Error())
}
qName := strings.ToLower(strings.TrimSuffix(q.Name, "."+domainSuffix))
if qName == strings.ToLower(hostname) {
m.Answer = append(m.Answer, mkAliasRecord(qName, node.ID()))
m.Answer = append(m.Answer, mkIDRecord(node.ID(), config.BuiltinAddr))
} else if p, found := config.PeerLookup.ByName[qName]; found {
m.Answer = append(m.Answer, mkAliasRecord(qName, p.ID))
m.Answer = append(m.Answer, mkIDRecord(p.ID, p.BuiltinAddr))
}
}
}
}
w.WriteMsg(m)
})
for _, netType := range []string{"tcp", "udp"} {
sv := &dns.Server{
Addr: "127.80.1.53:5380",
Net: netType,
ReusePort: true,
}
fmt.Printf("[-] Starting DNS server on /ip4/127.80.1.53/%s/5380\n", sv.Net)
go func(server *dns.Server) {
if err := server.ListenAndServe(); err != nil {
fmt.Printf("[!] DNS server error: %s, %s\n", server.Net, err.Error())
}
}(sv)
}
conn, err := resolved.NewConn()
if err != nil {
fmt.Println("[!] [dns] Failed to connect to D-Bus:", err)
return
}
defer conn.Close()
link, err := netlink.LinkByName(config.Interface)
if err != nil {
fmt.Println("[!] [dns] Failed to get link ID:", err)
return
}
linkID := link.Attrs().Index
for _, f := range [](func() error){
func() error {
return conn.SetLinkDNSEx(ctx, linkID, []resolved.LinkDNSEx{{
Family: syscall.AF_INET,
Address: []byte{127, 80, 1, 53},
Port: 5380,
}})
},
func() error {
return conn.SetLinkDomains(ctx, linkID, []resolved.LinkDomain{{
Domain: domainSuffix,
RoutingDomain: false,
}})
},
} {
if err := f(); err != nil {
fmt.Println("[!] [dns] Failed to configure resolved:", err)
return
}
}
}

View file

@ -1,128 +0,0 @@
module github.com/hyprspace/hyprspace
go 1.20
require (
github.com/DataDrake/cli-ng/v2 v2.0.2
github.com/iguanesolutions/go-systemd/v5 v5.1.1
github.com/libp2p/go-libp2p v0.31.0
github.com/libp2p/go-libp2p-kad-dht v0.25.0
github.com/multiformats/go-multiaddr v0.11.0
github.com/multiformats/go-multibase v0.2.0
github.com/prometheus/client_golang v1.16.0
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
github.com/vishvananda/netlink v1.1.0
)
require (
github.com/libp2p/go-libp2p-routing-helpers v0.7.0 // indirect
github.com/samber/lo v1.36.0 // indirect
)
require (
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/elastic/gosigar v0.14.2 // indirect
github.com/flynn/noise v1.0.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect
github.com/huin/goupnp v1.2.0 // indirect
github.com/ipfs/boxo v0.13.1
github.com/ipfs/go-cid v0.4.1 // indirect
github.com/ipfs/go-datastore v0.6.0 // indirect
github.com/ipfs/go-ipfs-util v0.0.3 // indirect
github.com/ipfs/go-log v1.0.5 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/ipld/go-ipld-prime v0.21.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect
github.com/klauspost/compress v1.16.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/koron/go-ssdp v0.0.4 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-cidranger v1.1.0 // indirect
github.com/libp2p/go-flow-metrics v0.1.0 // indirect
github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect
github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect
github.com/libp2p/go-libp2p-record v0.2.0 // indirect
github.com/libp2p/go-msgio v0.3.0 // indirect
github.com/libp2p/go-nat v0.2.0 // indirect
github.com/libp2p/go-netroute v0.2.1 // indirect
github.com/libp2p/go-reuseport v0.4.0 // indirect
github.com/libp2p/go-yamux/v4 v4.0.1 // indirect
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/miekg/dns v1.1.55
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
github.com/multiformats/go-multicodec v0.9.0 // indirect
github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-multistream v0.4.1 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
github.com/opencontainers/runtime-spec v1.1.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/polydawn/refmt v0.89.0 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.1 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-20 v0.3.3 // indirect
github.com/quic-go/quic-go v0.38.1 // indirect
github.com/quic-go/webtransport-go v0.5.3 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/smartystreets/assertions v1.13.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
github.com/yl2chen/cidranger v1.0.2
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel v1.16.0 // indirect
go.opentelemetry.io/otel/metric v1.16.0 // indirect
go.opentelemetry.io/otel/trace v1.16.0 // indirect
go.uber.org/dig v1.17.0 // indirect
go.uber.org/fx v1.20.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.25.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect
gonum.org/v1/gonum v0.14.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
lukechampine.com/blake3 v1.2.1 // indirect
)

View file

@ -1,611 +0,0 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDrake/cli-ng/v2 v2.0.2 h1:7+25l25VmlERCE95glW6QKBUF13vxqAM2jasFiN02xQ=
github.com/DataDrake/cli-ng/v2 v2.0.2/go.mod h1:bU9YaNNWWVq0eIdDsU3TCe9+7Jb398iBBoqee5EiKWQ=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU=
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4=
github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ=
github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f h1:pDhu5sgp8yJlEF/g6osliIIpF9K4F5jvkULXa4daRDQ=
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY=
github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/iguanesolutions/go-systemd/v5 v5.1.1 h1:Hs0Z16knPGCBFnKECrICPh+RQ89Sgy0xyzcalrHMKdw=
github.com/iguanesolutions/go-systemd/v5 v5.1.1/go.mod h1:Quv57scs6S7T0rC6qyLfW20KU/P4p9hrbLPF+ILYrXY=
github.com/ipfs/boxo v0.13.1 h1:nQ5oQzcMZR3oL41REJDcTbrvDvuZh3J9ckc9+ILeRQI=
github.com/ipfs/boxo v0.13.1/go.mod h1:btrtHy0lmO1ODMECbbEY1pxNtrLilvKSYLoGQt1yYCk=
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk=
github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk=
github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8=
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0=
github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs=
github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8=
github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo=
github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g=
github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk=
github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=
github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c=
github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic=
github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM=
github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro=
github.com/libp2p/go-libp2p v0.31.0 h1:LFShhP8F6xthWiBBq3euxbKjZsoRajVEyBS9snfHxYg=
github.com/libp2p/go-libp2p v0.31.0/go.mod h1:W/FEK1c/t04PbRH3fA9i5oucu5YcgrG0JVoBWT1B7Eg=
github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s=
github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w=
github.com/libp2p/go-libp2p-kad-dht v0.25.0 h1:T2SXQ/VlXTQVLChWY/+OyOsmGMRJvB5kiR+eJt7jtvI=
github.com/libp2p/go-libp2p-kad-dht v0.25.0/go.mod h1:P6fz+J+u4tPigvS5J0kxQ1isksqAhmXiS/pNaEw/nFI=
github.com/libp2p/go-libp2p-kbucket v0.6.3 h1:p507271wWzpy2f1XxPzCQG9NiN6R6lHL9GiSErbQQo0=
github.com/libp2p/go-libp2p-kbucket v0.6.3/go.mod h1:RCseT7AH6eJWxxk2ol03xtP9pEHetYSPXOaJnOiD8i0=
github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0=
github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk=
github.com/libp2p/go-libp2p-routing-helpers v0.7.0 h1:sirOYVD0wGWjkDwHZvinunIpaqPLBXkcnXApVHwZFGA=
github.com/libp2p/go-libp2p-routing-helpers v0.7.0/go.mod h1:R289GUxUMzRXIbWGSuUUTPrlVJZ3Y/pPz495+qgXJX8=
github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=
github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=
github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=
github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk=
github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk=
github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU=
github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ=
github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s=
github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU=
github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ=
github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo=
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8=
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms=
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc=
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU=
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc=
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
github.com/multiformats/go-multiaddr v0.11.0 h1:XqGyJ8ufbCE0HmTDwx2kPdsrQ36AGPZNZX6s6xfJH10=
github.com/multiformats/go-multiaddr v0.11.0/go.mod h1:gWUm0QLR4thQ6+ZF6SXUw8YjtwQSPapICM+NmCkxHSM=
github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A=
github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk=
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg=
github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k=
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=
github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo=
github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q=
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4=
github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM=
github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.38.1 h1:M36YWA5dEhEeT+slOu/SwMEucbYd0YFidxG3KlGPZaE=
github.com/quic-go/quic-go v0.38.1/go.mod h1:ijnZM7JsFIkp4cRyjxJNIzdSfCLmUMg9wdyhGmg+SN4=
github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU=
github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU=
github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/samber/lo v1.36.0 h1:4LaOxH1mHnbDGhTVE0i1z8v/lWaQW8AIfOD3HU4mSaw=
github.com/samber/lo v1.36.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs=
github.com/smartystreets/assertions v1.13.0/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8=
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI=
go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU=
go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ=
go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0=
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=

View file

@ -1,7 +0,0 @@
package main
import "github.com/hyprspace/hyprspace/cli"
func main() {
cli.Root.Run()
}

View file

@ -1 +0,0 @@
{"outs": [{"sha256": "baf010319e49e26c15063df091b495396442f5f3d4463093b86ed400569f5473", "size": 287300, "path": "hyprspace.png"}]}

View file

@ -1,62 +0,0 @@
package p2p
import (
"context"
"fmt"
"time"
"github.com/hyprspace/hyprspace/config"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
)
var discoverNow = make(chan bool)
// Discover starts up a DHT based discovery system finding and adding nodes with the same rendezvous string.
func Discover(ctx context.Context, h host.Host, dht *dht.IpfsDHT, peers []config.Peer) {
dur := time.Second * 1
ticker := time.NewTicker(dur)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-discoverNow:
dur = time.Second * 3
// Immediately trigger discovery
ticker.Reset(time.Millisecond * 1)
case <-ticker.C:
connectedToAny := false
for _, p := range peers {
if h.Network().Connectedness(p.ID) != network.Connected {
_, err := h.Network().DialPeer(ctx, p.ID)
if err != nil {
continue
}
connectedToAny = true
} else {
connectedToAny = true
}
}
if !connectedToAny {
fmt.Println("[!] Not connected to any peers, attempting to bootstrap again")
dht.Bootstrap(ctx)
dht.RefreshRoutingTable()
dur = time.Second * 10
ticker.Reset(dur)
} else {
dur = dur * 2
if dur >= time.Second*60 {
dur = time.Second * 60
}
ticker.Reset(dur)
}
}
}
}
func Rediscover() {
discoverNow <- true
}

View file

@ -1,55 +0,0 @@
package p2p
import (
"context"
"fmt"
"log"
"time"
"github.com/hyprspace/hyprspace/config"
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/p2p/protocol/ping"
)
func RouteMetricsService(ctx context.Context, host host.Host, cfg *config.Config) {
subCon, err := host.EventBus().Subscribe(new(event.EvtPeerConnectednessChanged))
if err != nil {
log.Fatal(err)
}
fmt.Println("[-] Route metrics service ready")
for {
select {
case <-ctx.Done():
return
case ev := <-subCon.Out():
evt := ev.(event.EvtPeerConnectednessChanged)
_, found := config.FindPeer(cfg.Peers, evt.Peer)
if found {
if evt.Connectedness == network.Connected {
ctx2, cancel := context.WithDeadline(ctx, time.Now().Add(30*time.Second))
ch := ping.Ping(ctx2, host, evt.Peer)
go func() {
t := time.NewTimer(15 * time.Second)
for {
select {
case <-t.C:
cancel()
case <-ctx2.Done():
return
case res := <-ch:
if res.Error == nil {
host.Peerstore().RecordLatency(evt.Peer, res.RTT)
}
time.Sleep(5 * time.Second)
}
}
}()
// wait a little before spawning another ping goroutine
time.Sleep(1 * time.Second)
}
}
}
}
}

View file

@ -1,318 +0,0 @@
package p2p
import (
"context"
"encoding/json"
"fmt"
"io"
"math/rand"
"net/http"
"net/url"
"os"
"time"
"github.com/hyprspace/hyprspace/config"
drclient "github.com/ipfs/boxo/routing/http/client"
"github.com/ipfs/boxo/routing/http/contentrouter"
"github.com/libp2p/go-libp2p"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p/core/connmgr"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/pnet"
"github.com/libp2p/go-libp2p/core/routing"
"github.com/libp2p/go-libp2p/p2p/discovery/backoff"
"github.com/libp2p/go-libp2p/p2p/host/autorelay"
routedhost "github.com/libp2p/go-libp2p/p2p/host/routed"
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
ma "github.com/multiformats/go-multiaddr"
)
var (
_ routing.Routing = &httpRoutingWrapper{}
)
// httpRoutingWrapper is a wrapper needed to construct the routing.Routing interface from
// http delegated routing.
type httpRoutingWrapper struct {
routing.ContentRouting
routing.PeerRouting
routing.ValueStore
}
func (c *httpRoutingWrapper) Bootstrap(ctx context.Context) error {
return nil
}
// Protocol is a descriptor for the Hyprspace P2P Protocol.
const Protocol = "/hyprspace/0.0.1"
var bootstrapTriggerChan = make(chan bool)
func getExtraPeers(addr ma.Multiaddr) (nodesList []string) {
nodesList = []string{}
ip4, err := addr.ValueForProtocol(ma.P_IP4)
if err != nil {
return
}
port, err := addr.ValueForProtocol(ma.P_TCP)
if err != nil {
return
}
resp, err := http.PostForm("http://"+ip4+":"+port+"/api/v0/swarm/peers", url.Values{})
if err != nil {
return
}
defer resp.Body.Close()
apiResponse, err := io.ReadAll(resp.Body)
if err != nil {
return
}
var obj = map[string][]map[string]interface{}{}
json.Unmarshal([]byte(apiResponse), &obj)
for _, v := range obj["Peers"] {
nodesList = append(nodesList, (v["Addr"].(string) + "/p2p/" + v["Peer"].(string)))
}
return
}
func getExtraBootstrapNodes(addr ma.Multiaddr) (nodesList []string) {
nodesList = []string{}
ip4, err := addr.ValueForProtocol(ma.P_IP4)
if err != nil {
return
}
port, err := addr.ValueForProtocol(ma.P_TCP)
if err != nil {
return
}
resp, err := http.PostForm("http://"+ip4+":"+port+"/api/v0/bootstrap", url.Values{})
if err != nil {
return
}
defer resp.Body.Close()
apiResponse, err := io.ReadAll(resp.Body)
if err != nil {
return
}
var obj = map[string][]string{}
json.Unmarshal([]byte(apiResponse), &obj)
return obj["Peers"]
}
// CreateNode creates an internal Libp2p nodes and returns it and it's DHT Discovery service.
func CreateNode(ctx context.Context, privateKey crypto.PrivKey, listenAddreses []ma.Multiaddr, handler network.StreamHandler, acl relay.ACLFilter, gater connmgr.ConnectionGater, vpnPeers []config.Peer) (node host.Host, dhtOut *dht.IpfsDHT, err error) {
maybePrivateNet := libp2p.ChainOptions()
swarmKeyFile, ok := os.LookupEnv("HYPRSPACE_SWARM_KEY")
if ok {
fmt.Println("[+] Using swarm key " + swarmKeyFile)
var swarmKey *os.File
swarmKey, err = os.Open(swarmKeyFile)
if err != nil {
return
}
defer swarmKey.Close()
key, _ := pnet.DecodeV1PSK(swarmKey)
maybePrivateNet = libp2p.PrivateNetwork(key)
}
peerChan := make(chan peer.AddrInfo)
// Create libp2p node
basicHost, err := libp2p.New(
maybePrivateNet,
libp2p.ListenAddrs(listenAddreses...),
libp2p.Identity(privateKey),
libp2p.UserAgent("hyprspace"),
libp2p.DefaultSecurity,
libp2p.ConnectionGater(gater),
libp2p.NATPortMap(),
libp2p.DefaultMuxers,
libp2p.Transport(libp2pquic.NewTransport),
libp2p.Transport(tcp.NewTCPTransport),
libp2p.EnableHolePunching(),
libp2p.EnableRelayService(relay.WithLimit(nil), relay.WithACL(acl)),
libp2p.EnableNATService(),
libp2p.EnableAutoRelayWithPeerSource(
func(ctx context.Context, numPeers int) <-chan peer.AddrInfo {
r := make(chan peer.AddrInfo)
go func() {
defer close(r)
for ; numPeers != 0; numPeers-- {
select {
case v, ok := <-peerChan:
if !ok {
return
}
select {
case r <- v:
case <-ctx.Done():
return
}
case <-ctx.Done():
return
}
}
}()
return r
},
autorelay.WithNumRelays(2),
autorelay.WithBootDelay(10*time.Second),
),
libp2p.WithDialTimeout(time.Second*5),
libp2p.FallbackDefaults,
)
if err != nil {
return
}
// Define Bootstrap Nodes.
peers := []string{
"/ip4/152.67.75.145/tcp/110/p2p/12D3KooWQWsHPUUeFhe4b6pyCaD1hBoj8j6Z7S7kTznRTh1p1eVt",
"/ip4/152.67.75.145/udp/110/quic-v1/p2p/12D3KooWQWsHPUUeFhe4b6pyCaD1hBoj8j6Z7S7kTznRTh1p1eVt",
"/ip4/152.67.75.145/tcp/995/p2p/QmbrAHuh4RYcyN9fWePCZMVmQjbaNXtyvrDCWz4VrchbXh",
"/ip4/152.67.75.145/udp/995/quic-v1/p2p/QmbrAHuh4RYcyN9fWePCZMVmQjbaNXtyvrDCWz4VrchbXh",
"/ip4/95.216.8.12/tcp/110/p2p/Qmd7QHZU8UjfYdwmjmq1SBh9pvER9AwHpfwQvnvNo3HBBo",
"/ip4/95.216.8.12/udp/110/quic-v1/p2p/Qmd7QHZU8UjfYdwmjmq1SBh9pvER9AwHpfwQvnvNo3HBBo",
"/ip4/95.216.8.12/tcp/995/p2p/QmYs4xNBby2fTs8RnzfXEk161KD4mftBfCiR8yXtgGPj4J",
"/ip4/95.216.8.12/udp/995/quic-v1/p2p/QmYs4xNBby2fTs8RnzfXEk161KD4mftBfCiR8yXtgGPj4J",
"/ip4/152.67.73.164/tcp/995/p2p/12D3KooWL84sAtq1QTYwb7gVbhSNX5ZUfVt4kgYKz8pdif1zpGUh",
"/ip4/152.67.73.164/udp/995/quic-v1/p2p/12D3KooWL84sAtq1QTYwb7gVbhSNX5ZUfVt4kgYKz8pdif1zpGUh",
"/ip4/37.27.11.202/udp/21/quic-v1/p2p/12D3KooWN31twBvdEcxz2jTv4tBfPe3mkNueBwDJFCN4xn7ZwFbi",
"/ip4/37.27.11.202/udp/443/quic-v1/p2p/12D3KooWN31twBvdEcxz2jTv4tBfPe3mkNueBwDJFCN4xn7ZwFbi",
"/ip4/37.27.11.202/udp/500/quic-v1/p2p/12D3KooWN31twBvdEcxz2jTv4tBfPe3mkNueBwDJFCN4xn7ZwFbi",
"/ip4/37.27.11.202/udp/995/quic-v1/p2p/12D3KooWN31twBvdEcxz2jTv4tBfPe3mkNueBwDJFCN4xn7ZwFbi",
"/dnsaddr/bootstrap.libp2p.io/p2p/12D3KooWEZXjE41uU4EL2gpkAQeDXYok6wghN7wwNVPF5bwkaNfS",
"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
"/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
"/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp",
"/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
"/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
}
// Convert Bootstap Nodes into usable addresses.
staticBootstrapPeers, err := parsePeerAddrs(peers)
if err != nil {
return node, nil, err
}
ipfsApiStr, ok := os.LookupEnv("HYPRSPACE_IPFS_API")
if ok {
ipfsApiAddr, err := ma.NewMultiaddr(ipfsApiStr)
if err == nil {
fmt.Println("[+] Getting additional peers from IPFS API")
extraPeers, err := parsePeerAddrs(getExtraPeers(ipfsApiAddr))
if err == nil {
fmt.Printf("[+] %d additional addresses\n", len(extraPeers))
for _, p := range extraPeers {
basicHost.Peerstore().AddAddrs(p.ID, p.Addrs, 5*time.Minute)
}
}
}
}
// Create DHT Subsystem
dhtOut, err = dht.New(
ctx,
basicHost,
dht.Mode(dht.ModeClient),
dht.BootstrapPeers(staticBootstrapPeers...),
dht.BootstrapPeersFunc(func() []peer.AddrInfo {
extraBootstrapNodes := []string{}
ipfsApiStr, ok := os.LookupEnv("HYPRSPACE_IPFS_API")
if ok {
ipfsApiAddr, err := ma.NewMultiaddr(ipfsApiStr)
if err == nil {
fmt.Println("[+] Getting additional bootstrap nodes from IPFS API")
extraBootstrapNodes = getExtraBootstrapNodes(ipfsApiAddr)
fmt.Printf("[+] %d additional bootstrap nodes\n", len(extraBootstrapNodes))
}
}
dynamicBootstrapPeers, err := parsePeerAddrs(extraBootstrapNodes)
if err != nil {
return staticBootstrapPeers
} else {
return append(staticBootstrapPeers, dynamicBootstrapPeers...)
}
}),
)
transport := http.DefaultTransport.(*http.Transport).Clone()
transport.MaxIdleConns = 500
transport.MaxIdleConnsPerHost = 100
delegateHTTPClient := &http.Client{
Transport: &drclient.ResponseBodyLimitedTransport{
RoundTripper: transport,
LimitBytes: 1 << 20,
},
}
dr, err := drclient.New(
"https://p2p.privatevoid.net",
drclient.WithHTTPClient(delegateHTTPClient),
drclient.WithIdentity(privateKey),
drclient.WithUserAgent("hyprspace"),
)
if err != nil {
return node, nil, err
}
cr := contentrouter.NewContentRoutingClient(dr)
pexr := PeXRouting{basicHost, vpnPeers}
pr := ParallelRouting{[]routedhost.Routing{pexr, dhtOut, httpRoutingWrapper{
ContentRouting: cr,
PeerRouting: cr,
ValueStore: cr,
}}}
node = routedhost.Wrap(basicHost, pr)
// Setup Hyprspace Stream Handler
node.SetStreamHandler(Protocol, handler)
if err != nil {
return node, nil, err
}
// Continuously feed peers into the AutoRelay service
go func() {
delay := backoff.NewExponentialDecorrelatedJitter(time.Second, time.Second*60, 5.0, rand.NewSource(time.Now().UnixMilli()))()
for {
for _, p := range node.Network().Peers() {
pi := node.Network().Peerstore().PeerInfo(p)
if acl.AllowReserve(p, node.Addrs()[0]) {
peerChan <- pi
}
}
time.Sleep(delay.Delay())
}
}()
return node, dhtOut, nil
}
func parsePeerAddrs(peers []string) (addrs []peer.AddrInfo, err error) {
for _, addrStr := range peers {
addr, err := ma.NewMultiaddr(addrStr)
if err != nil {
return nil, err
}
pii, err := peer.AddrInfoFromP2pAddr(addr)
if err != nil {
return nil, err
}
addrs = append(addrs, *pii)
}
return addrs, nil
}

View file

@ -1,186 +0,0 @@
package p2p
import (
"bufio"
"context"
"fmt"
"io"
"log"
"strings"
"time"
"github.com/hyprspace/hyprspace/config"
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/routing"
"github.com/multiformats/go-multiaddr"
)
type PeXRouting struct {
host host.Host
vpnPeers []config.Peer
}
const PeXProtocol = "/hyprspace/pex/0.0.1"
func checkErrPeX(err error, stream network.Stream) bool {
if err != nil {
stream.Reset()
fmt.Println("[!] PeX:", err)
return true
}
return false
}
func NewPeXStreamHandler(host host.Host, cfg *config.Config) func(network.Stream) {
return func(stream network.Stream) {
found := false
for _, p := range cfg.Peers {
if p.ID == stream.Conn().RemotePeer() {
found = true
break
}
}
if !found {
stream.Reset()
return
}
buf := bufio.NewReader(stream)
str, err := buf.ReadString('\n')
if checkErrPeX(err, stream) {
return
}
str = strings.TrimSuffix(str, "\n")
if str == "r" {
// peer requests addresses
for _, p := range cfg.Peers {
if p.ID != stream.Conn().RemotePeer() {
for _, a := range host.Peerstore().Addrs(p.ID) {
_, err := stream.Write([]byte(fmt.Sprintf("%s|%s\n", p.ID, a)))
if checkErrPeX(err, stream) {
return
}
}
}
}
stream.Close()
}
}
}
func RequestPeX(ctx context.Context, host host.Host, peers []peer.ID) (addrInfos []peer.AddrInfo, e error) {
for _, p := range peers {
s, err := host.NewStream(ctx, p, PeXProtocol)
if err != nil {
return nil, err
}
s.Write([]byte("r\n"))
s.SetDeadline(time.Now().Add(10 * time.Second))
buf := bufio.NewReader(s)
for {
str, err := buf.ReadString('\n')
if err == io.EOF {
s.Close()
return addrInfos, nil
} else if checkErrPeX(err, s) {
s.Close()
return nil, err
}
str = strings.TrimSuffix(str, "\n")
splits := strings.Split(str, "|")
idStr := splits[0]
addrStr := splits[1]
peerId, err := peer.Decode(idStr)
if checkErrPeX(err, s) {
s.Close()
return nil, err
}
ma, err := multiaddr.NewMultiaddr(addrStr)
if checkErrPeX(err, s) {
s.Close()
return nil, err
}
addrInfos = append(addrInfos, peer.AddrInfo{
ID: peerId,
Addrs: []multiaddr.Multiaddr{ma},
})
}
}
return addrInfos, nil
}
func PeXService(ctx context.Context, host host.Host, cfg *config.Config) {
subCon, err := host.EventBus().Subscribe(new(event.EvtPeerConnectednessChanged))
if err != nil {
log.Fatal(err)
}
fmt.Println("[-] PeX service ready")
for {
select {
case <-ctx.Done():
return
case ev := <-subCon.Out():
evt := ev.(event.EvtPeerConnectednessChanged)
for _, vpnPeer := range cfg.Peers {
if vpnPeer.ID == evt.Peer {
if evt.Connectedness == network.Connected {
go func() {
addrInfos, err := RequestPeX(ctx, host, []peer.ID{evt.Peer})
if err == nil {
for _, addrInfo := range addrInfos {
host.Peerstore().AddAddrs(addrInfo.ID, addrInfo.Addrs, 30*time.Second)
go host.Connect(ctx, addrInfo)
}
}
}()
} else if evt.Connectedness == network.NotConnected {
peers := []peer.ID{}
for _, p := range cfg.Peers {
peers = append(peers, p.ID)
}
go func() {
addrInfos, err := RequestPeX(ctx, host, peers)
if err == nil {
for _, addrInfo := range addrInfos {
host.Peerstore().AddAddrs(addrInfo.ID, addrInfo.Addrs, 30*time.Second)
go host.Connect(ctx, addrInfo)
}
}
}()
}
break
}
}
}
}
}
func (pexr PeXRouting) FindPeer(ctx context.Context, targetPeer peer.ID) (peer.AddrInfo, error) {
found := false
peers := []peer.ID{}
addrInfo := peer.AddrInfo{
ID: targetPeer,
}
for _, p := range pexr.vpnPeers {
peers = append(peers, p.ID)
if p.ID == targetPeer {
found = true
}
}
// PeX routing only returns VPN node addresses
if !found {
return addrInfo, routing.ErrNotFound
}
addrInfos, err := RequestPeX(ctx, pexr.host, peers)
if err != nil {
return addrInfo, err
}
for _, ai := range addrInfos {
if ai.ID == targetPeer {
addrInfo.Addrs = append(addrInfo.Addrs, ai.Addrs...)
}
}
return addrInfo, nil
}

View file

@ -1,29 +0,0 @@
package p2p
import (
"github.com/hyprspace/hyprspace/config"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
"github.com/multiformats/go-multiaddr"
)
type ClosedCircuitRelayFilter struct {
allowedPeers []config.Peer
}
func (ccr ClosedCircuitRelayFilter) AllowReserve(p peer.ID, a multiaddr.Multiaddr) bool {
_, found := config.FindPeer(ccr.allowedPeers, p)
return found
}
func (ccr ClosedCircuitRelayFilter) AllowConnect(src peer.ID, srcAddr multiaddr.Multiaddr, dest peer.ID) bool {
_, foundSrc := config.FindPeer(ccr.allowedPeers, src)
_, foundDst := config.FindPeer(ccr.allowedPeers, dest)
return foundSrc || foundDst
}
func NewClosedCircuitRelayFilter(allowedPeers []config.Peer) relay.ACLFilter {
return ClosedCircuitRelayFilter{
allowedPeers: allowedPeers,
}
}

View file

@ -1,97 +0,0 @@
package p2p
import (
"context"
"net"
"sync"
"time"
"github.com/hyprspace/hyprspace/config"
"github.com/libp2p/go-libp2p/core/control"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
routedhost "github.com/libp2p/go-libp2p/p2p/host/routed"
ma "github.com/multiformats/go-multiaddr"
"github.com/vishvananda/netlink"
)
type ParallelRouting struct {
routings []routedhost.Routing
}
func (pr ParallelRouting) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, error) {
var wg sync.WaitGroup
var mutex sync.Mutex
var info peer.AddrInfo
info.ID = p
subCtx, cancelSubCtx := context.WithTimeout(ctx, 30*time.Second)
for _, r := range pr.routings {
wg.Add(1)
r2 := r
go func() {
defer wg.Done()
ai, err := r2.FindPeer(subCtx, p)
if err == nil {
mutex.Lock()
defer mutex.Unlock()
info.Addrs = append(info.Addrs, ai.Addrs...)
// give the other routings a short time period to find a better address
time.AfterFunc(500*time.Millisecond, cancelSubCtx)
}
}()
}
wg.Wait()
cancelSubCtx()
return info, nil
}
type RecursionGater struct {
config *config.Config
ifindex int
}
func NewRecursionGater(config *config.Config) RecursionGater {
link, err := netlink.LinkByName(config.Interface)
if err != nil {
panic(err)
}
return RecursionGater{
config: config,
ifindex: link.Attrs().Index,
}
}
func (rg RecursionGater) InterceptAddrDial(pid peer.ID, addr ma.Multiaddr) bool {
if ip4str, err := addr.ValueForProtocol(ma.P_IP4); err == nil {
ip4 := net.ParseIP(ip4str)
if rte, ok := rg.config.FindRouteForIP(ip4); ok {
if rte.Target.ID == pid {
routes, err := netlink.RouteGet(ip4)
if err == nil {
if len(routes) > 0 && routes[0].LinkIndex == rg.ifindex {
return false
}
}
}
}
}
return true
}
func (rg RecursionGater) InterceptPeerDial(pid peer.ID) bool {
return true
}
func (rg RecursionGater) InterceptAccept(addrs network.ConnMultiaddrs) bool {
return true
}
func (rg RecursionGater) InterceptSecured(direction network.Direction, pid peer.ID, addrs network.ConnMultiaddrs) bool {
return true
}
func (rg RecursionGater) InterceptUpgraded(network.Conn) (bool, control.DisconnectReason) {
return true, 0
}

View file

@ -1,46 +0,0 @@
{ lib, inputs, ... }:
{
perSystem = { pkgs, ... }: {
projectShells.hyprspace = {
tools = [
pkgs.go_1_20
];
env.GOPATH.eval = "$REPO_DATA_DIR/go";
};
packages.hyprspace = with pkgs; buildGo120Module rec {
pname = "hyprspace";
version = "0.8.5";
src = with inputs.nix-filter.lib; let
dirs = map inDirectory;
in filter {
root = ./.;
include = [
"go.mod"
"go.sum"
(matchExt "go")
] ++ (dirs [
"cli"
"config"
"dns"
"p2p"
"rpc"
"tun"
]);
};
vendorHash = "sha256-VBCgFbJixBh+pKfYGJVapHqWBpUFfvjl1cwOER2Li6Y=";
ldflags = [ "-s" "-w" "-X github.com/hyprspace/hyprspace/cli.appVersion=${version}" ];
meta = with lib; {
description = "A Lightweight VPN Built on top of Libp2p for Truly Distributed Networks.";
homepage = "https://github.com/hyprspace/hyprspace";
license = licenses.asl20;
maintainers = with maintainers; [ yusdacra ];
platforms = platforms.linux ++ platforms.darwin;
};
};
};
}

View file

@ -1,42 +0,0 @@
package rpc
import (
"fmt"
"log"
"net/rpc"
)
func connect(ifname string) *rpc.Client {
client, err := rpc.Dial("unix", fmt.Sprintf("/run/hyprspace-rpc.%s.sock", ifname))
if err != nil {
log.Fatal("[!] Failed to connect to RPC server: ", err)
}
return client
}
func Status(ifname string) StatusReply {
client := connect(ifname)
var reply StatusReply
if err := client.Call("HyprspaceRPC.Status", new(Args), &reply); err != nil {
log.Fatal("[!] RPC call failed: ", err)
}
return reply
}
func Peers(ifname string) PeersReply {
client := connect(ifname)
var reply PeersReply
if err := client.Call("HyprspaceRPC.Peers", new(Args), &reply); err != nil {
log.Fatal("[!] RPC call failed: ", err)
}
return reply
}
func Route(ifname string, args RouteArgs) RouteReply {
client := connect(ifname)
var reply RouteReply
if err := client.Call("HyprspaceRPC.Route", args, &reply); err != nil {
log.Fatal("[!] RPC call failed: ", err)
}
return reply
}

View file

@ -1,180 +0,0 @@
package rpc
import (
"context"
"errors"
"fmt"
"log"
"net"
"net/rpc"
"os"
"github.com/hyprspace/hyprspace/config"
"github.com/hyprspace/hyprspace/p2p"
"github.com/hyprspace/hyprspace/tun"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
"github.com/yl2chen/cidranger"
)
type HyprspaceRPC struct {
host host.Host
config config.Config
tunDev tun.TUN
}
func (hsr *HyprspaceRPC) Status(args *Args, reply *StatusReply) error {
netPeersCurrent := 0
var netPeerAddrsCurrent []string
for _, p := range hsr.config.Peers {
if hsr.host.Network().Connectedness(p.ID) == network.Connected {
netPeersCurrent = netPeersCurrent + 1
for _, c := range hsr.host.Network().ConnsToPeer(p.ID) {
netPeerAddrsCurrent = append(netPeerAddrsCurrent, fmt.Sprintf("@%s (%s) %s/p2p/%s",
p.Name,
hsr.host.Peerstore().LatencyEWMA(p.ID).String(),
c.RemoteMultiaddr().String(),
p.ID.String(),
))
}
}
}
var addrStrings []string
for _, ma := range hsr.host.Addrs() {
addrStrings = append(addrStrings, ma.String())
}
*reply = StatusReply{
hsr.host.ID().String(),
len(hsr.host.Network().Conns()),
netPeersCurrent,
netPeerAddrsCurrent,
len(hsr.config.Peers),
addrStrings,
}
return nil
}
func (hsr *HyprspaceRPC) Route(args *RouteArgs, reply *RouteReply) error {
switch args.Action {
case Show:
var routeInfos []RouteInfo
allRoutes, err := hsr.config.PeerLookup.ByRoute.CoveredNetworks(*cidranger.AllIPv4)
if err != nil {
return err
}
for _, r := range allRoutes {
rte := *r.(*config.RouteTableEntry)
connected := hsr.host.Network().Connectedness(rte.Target.ID) == network.Connected
relay := false
relayAddr := rte.Target.ID
if connected {
ConnLoop:
for _, c := range hsr.host.Network().ConnsToPeer(rte.Target.ID) {
for _, s := range c.GetStreams() {
if s.Protocol() == p2p.Protocol {
if _, err := c.RemoteMultiaddr().ValueForProtocol(multiaddr.P_CIRCUIT); err == nil {
relay = true
if ra, err := c.RemoteMultiaddr().ValueForProtocol(multiaddr.P_P2P); err == nil {
relayAddr, err = peer.Decode(ra)
if err != nil {
relayAddr = rte.Target.ID
}
}
} else {
relay = false
relayAddr = rte.Target.ID
break ConnLoop
}
}
}
}
}
routeInfos = append(routeInfos, RouteInfo{
Network: rte.Network(),
TargetName: rte.Target.Name,
TargetAddr: rte.Target.ID,
RelayAddr: relayAddr,
IsRelay: relay,
IsConnected: connected,
})
}
*reply = RouteReply{
Routes: routeInfos,
}
case Add:
if len(args.Args) != 2 {
return errors.New("expected exactly 2 arguments")
}
_, network, err := net.ParseCIDR(args.Args[0])
if err != nil {
return err
}
target, found := config.FindPeerByCLIRef(hsr.config.Peers, args.Args[1])
if !found {
return errors.New("no such peer")
}
err = hsr.tunDev.Apply(tun.Route(*network))
if err != nil {
return err
}
hsr.config.PeerLookup.ByRoute.Insert(&config.RouteTableEntry{
Net: *network,
Target: *target,
})
case Del:
if len(args.Args) != 1 {
return errors.New("expected exactly 1 argument")
}
_, network, err := net.ParseCIDR(args.Args[0])
if err != nil {
return err
}
err = hsr.tunDev.Apply(tun.RemoveRoute(*network))
if err != nil {
return err
}
_, err = hsr.config.PeerLookup.ByRoute.Remove(*network)
if err != nil {
_ = hsr.tunDev.Apply(tun.Route(*network))
return err
}
default:
return errors.New("no such action")
}
return nil
}
func (hsr *HyprspaceRPC) Peers(args *Args, reply *PeersReply) error {
var peerAddrs []string
for _, c := range hsr.host.Network().Conns() {
peerAddrs = append(peerAddrs, fmt.Sprintf("%s/p2p/%s", c.RemoteMultiaddr().String(), c.RemotePeer().String()))
}
*reply = PeersReply{peerAddrs}
return nil
}
func RpcServer(ctx context.Context, ma multiaddr.Multiaddr, host host.Host, config config.Config, tunDev tun.TUN) {
hsr := HyprspaceRPC{host, config, tunDev}
rpc.Register(&hsr)
addr, err := ma.ValueForProtocol(multiaddr.P_UNIX)
if err != nil {
log.Fatal("[!] Failed to parse multiaddr: ", err)
}
var lc net.ListenConfig
l, err := lc.Listen(ctx, "unix", addr)
os.Chmod(addr, 0o0770)
if err != nil {
log.Fatal("[!] Failed to launch RPC server: ", err)
}
fmt.Println("[-] RPC server ready")
go rpc.Accept(l)
<-ctx.Done()
fmt.Println("[-] Closing RPC server")
l.Close()
}

View file

@ -1,51 +0,0 @@
package rpc
import (
"net"
"github.com/libp2p/go-libp2p/core/peer"
)
type Args struct {
}
type StatusReply struct {
PeerID string
SwarmPeersCurrent int
NetPeersCurrent int
NetPeerAddrsCurrent []string
NetPeersMax int
ListenAddrs []string
}
type PeersReply struct {
PeerAddrs []string
}
type RouteAction string
const (
Show RouteAction = "show"
Add = "add"
Del = "del"
)
type RouteInfo struct {
Network net.IPNet
TargetName string
TargetAddr peer.ID
RelayAddr peer.ID
IsRelay bool
IsConnected bool
}
type RouteArgs struct {
Action RouteAction
Args []string
}
type RouteReply struct {
Out string
Routes []RouteInfo
Err error
}

View file

@ -1,44 +0,0 @@
package tun
import "net"
// Option defines a TUN device modifier option.
type Option func(tun *TUN) error
// Address sets the local address and subnet for an interface.
// On MacOS devices use this function to set the Src Address
// for an interface and use DestAddress to set the destination ip.
func Address(address string) Option {
return func(tun *TUN) error {
return tun.setAddress(address)
}
}
// MTU sets the Maximum Transmission Unit size for an interface.
func MTU(mtu int) Option {
return func(tun *TUN) error {
return tun.setMTU(mtu)
}
}
// DestAddress sets the destination address for a point-to-point interface.
// Only use this option on MacOS devices.
func DestAddress(address string) Option {
return func(tun *TUN) error {
return tun.setDestAddress(address)
}
}
// Route adds an entry to the system route table
func Route(dest net.IPNet) Option {
return func(tun *TUN) error {
return tun.addRoute(dest)
}
}
// RemoveRoute removes an entry from the system route table
func RemoveRoute(dest net.IPNet) Option {
return func(tun *TUN) error {
return tun.delRoute(dest)
}
}

View file

@ -1,26 +0,0 @@
package tun
import "github.com/songgao/water"
// TUN is a struct containing the fields necessary
// to configure a system TUN device. Access the
// internal TUN device through TUN.Iface
type TUN struct {
Iface *water.Interface
MTU int
Src string
Dst string
}
// Apply configures the specified options for a TUN device.
func (t *TUN) Apply(opts ...Option) error {
for _, opt := range opts {
if opt == nil {
continue
}
if err := opt(t); err != nil {
return err
}
}
return nil
}

View file

@ -1,72 +0,0 @@
//go:build darwin
// +build darwin
package tun
import (
"fmt"
"os/exec"
"github.com/songgao/water"
)
// New creates and returns a new TUN interface for the application.
func New(name string, opts ...Option) (*TUN, error) {
// Setup TUN Config
cfg := water.Config{
DeviceType: water.TUN,
}
// Create Water Interface
iface, err := water.New(cfg)
if err != nil {
return nil, err
}
// Create TUN result struct
result := TUN{
Iface: iface,
}
// Apply options to set TUN config values
err = result.Apply(opts...)
return &result, err
}
// SetMTU sets the Maximum Tansmission Unit Size for a
// Packet on the interface.
func (t *TUN) setMTU(mtu int) error {
return ifconfig(t.Iface.Name(), "mtu", fmt.Sprintf("%d", mtu))
}
// SetDestAddress sets the interface's address.
func (t *TUN) setAddress(address string) error {
t.Src = address
return nil
}
// SetDestAddress sets the interface's address.
func (t *TUN) setDestAddress(address string) error {
t.Dst = address
return nil
}
// Up brings up an interface to allow it to start accepting connections.
func (t *TUN) Up() error {
return ifconfig(t.Iface.Name(), "inet", t.Src, t.Dst, "up")
}
// Down brings down an interface stopping active connections.
func (t *TUN) Down() error {
return ifconfig(t.Iface.Name(), "down")
}
// Delete removes a TUN device from the host.
func Delete(name string) error {
return fmt.Errorf("removing an interface is unsupported under mac")
}
func ifconfig(args ...string) error {
cmd := exec.Command("ifconfig", args...)
return cmd.Run()
}

View file

@ -1,117 +0,0 @@
//go:build linux
// +build linux
package tun
import (
"errors"
"net"
"github.com/songgao/water"
"github.com/vishvananda/netlink"
)
// New creates and returns a new TUN interface for the application.
func New(name string, opts ...Option) (*TUN, error) {
// Setup TUN Config
cfg := water.Config{
DeviceType: water.TUN,
}
cfg.Name = name
// Create Water Interface
iface, err := water.New(cfg)
if err != nil {
return nil, err
}
// Create TUN result struct
result := TUN{
Iface: iface,
}
// Apply options to set TUN config values
err = result.Apply(opts...)
return &result, err
}
// setMTU sets the Maximum Tansmission Unit Size for a
// Packet on the interface.
func (t *TUN) setMTU(mtu int) error {
link, err := netlink.LinkByName(t.Iface.Name())
if err != nil {
return err
}
return netlink.LinkSetMTU(link, mtu)
}
// setDestAddress sets the interface's destination address and subnet.
func (t *TUN) setAddress(address string) error {
addr, err := netlink.ParseAddr(address)
if err != nil {
return err
}
link, err := netlink.LinkByName(t.Iface.Name())
if err != nil {
return err
}
return netlink.AddrAdd(link, addr)
}
// SetDestAddress isn't supported under Linux.
// You should instead use set address to set the interface to handle
// all addresses within a subnet.
func (t *TUN) setDestAddress(address string) error {
return errors.New("destination addresses are not supported under linux")
}
func (t *TUN) addRoute(network net.IPNet) error {
link, err := netlink.LinkByName(t.Iface.Name())
if err != nil {
return err
}
return netlink.RouteAdd(&netlink.Route{
LinkIndex: link.Attrs().Index,
Dst: &network,
Priority: 3000,
})
}
func (t *TUN) delRoute(network net.IPNet) error {
link, err := netlink.LinkByName(t.Iface.Name())
if err != nil {
return err
}
return netlink.RouteDel(&netlink.Route{
LinkIndex: link.Attrs().Index,
Dst: &network,
Priority: 3000,
})
}
// Up brings up an interface to allow it to start accepting connections.
func (t *TUN) Up() error {
link, err := netlink.LinkByName(t.Iface.Name())
if err != nil {
return err
}
return netlink.LinkSetUp(link)
}
// Down brings down an interface stopping active connections.
func (t *TUN) Down() error {
link, err := netlink.LinkByName(t.Iface.Name())
if err != nil {
return err
}
return netlink.LinkSetDown(link)
}
// Delete removes a TUN device from the host.
func Delete(name string) error {
link, err := netlink.LinkByName(name)
if err != nil {
return err
}
return netlink.LinkDel(link)
}

View file

@ -1,127 +0,0 @@
//go:build windows
// +build windows
package tun
import (
"errors"
"fmt"
"net"
"os/exec"
"github.com/songgao/water"
)
// New creates and returns a new TUN interface for the application.
func New(name string, opts ...Option) (*TUN, error) {
result := TUN{}
// Apply options early to set struct values for interface creation.
err := result.Apply(opts...)
if err != nil {
return nil, err
}
// TUN on Windows requires address and network to be set on device creation stage
// We also set network to 0.0.0.0/0 so we able to reach networks behind the node
// https://github.com/songgao/water/blob/master/params_windows.go
// https://gitlab.com/openconnect/openconnect/-/blob/master/tun-win32.c
ip, _, err := net.ParseCIDR(result.Src)
if err != nil {
return nil, err
}
network := net.IPNet{
IP: ip,
Mask: net.IPv4Mask(0, 0, 0, 0),
}
// Setup TUN Config
cfg := water.Config{
DeviceType: water.TUN,
PlatformSpecificParams: water.PlatformSpecificParams{
ComponentID: "tap0901",
InterfaceName: name,
Network: network.String(),
},
}
// Interface should be enabled before creation of water interface
// Otherwise there will be an error "The system cannot find the file specified."
netsh("interface", "set", "interface", "name=", name, "enable")
// Create Water Interface
iface, err := water.New(cfg)
if err != nil {
return nil, err
}
// Set TUN interface to newly created interface
result.Iface = iface
// Apply options to setup TUN interface configuration
// Setup interface address
err = result.setupAddress(result.Src)
if err != nil {
return nil, err
}
// Setup interface mtu size
err = result.setupMTU(result.MTU)
if err != nil {
return nil, err
}
return &result, err
}
// setMTU configures the interface's MTU.
func (t *TUN) setMTU(mtu int) error {
t.MTU = mtu
return nil
}
// setAddress configures the interface's address.
func (t *TUN) setAddress(address string) error {
t.Src = address
return nil
}
// setupMTU sets the Maximum Tansmission Unit Size for a
// Packet on the interface.
func (t *TUN) setupMTU(mtu int) error {
return netsh("interface", "ipv4", "set", "subinterface", t.Iface.Name(), "mtu=", fmt.Sprintf("%d", mtu))
}
// setupAddress sets the interface's destination address and subnet.
func (t *TUN) setupAddress(address string) error {
return netsh("interface", "ip", "set", "address", "name=", t.Iface.Name(), "static", address)
}
// SetDestAddress isn't supported under Windows.
// You should instead use set address to set the interface to handle
// all addresses within a subnet.
func (t *TUN) setDestAddress(address string) error {
return errors.New("destination addresses are not supported under windows")
}
// Up brings up an interface to allow it to start accepting connections.
func (t *TUN) Up() error {
return nil
}
// Down brings down an interface stopping active connections.
func (t *TUN) Down() error {
return nil
}
// Delete removes a TUN device from the host.
func Delete(name string) error {
return netsh("interface", "set", "interface", "name=", name, "disable")
}
func netsh(args ...string) (err error) {
cmd := exec.Command("netsh", args...)
err = cmd.Run()
return
}

View file

@ -12,11 +12,11 @@ super: rec {
garage = patch super.garage_0_8 "patches/base/garage";
jellyfin = patch (super.jellyfin.override {
jellyfin = super.jellyfin.override {
ffmpeg = super.ffmpeg.override {
withMfx = true;
};
}) "patches/base/jellyfin";
};
jre17_standard = let
jre = super.jre_minimal.override {
@ -38,7 +38,7 @@ super: rec {
kanidm = patch super.kanidm "patches/base/kanidm";
keycloak = super.keycloak.override {
keycloak = super.callPackage ./security/keycloak {
jre = jre17_standard;
};

View file

@ -6,7 +6,6 @@
./modules/devshell.nix
./build-support
./networking/hyprspace/project.nix
./networking/ipfs-cluster/project.nix
./servers/reflex-cache/project.nix
./websites/landing/project.nix

View file

@ -0,0 +1,9 @@
{ callPackage }:
{
scim-for-keycloak = callPackage ./scim-for-keycloak {};
scim-keycloak-user-storage-spi = callPackage ./scim-keycloak-user-storage-spi {};
keycloak-discord = callPackage ./keycloak-discord {};
keycloak-metrics-spi = callPackage ./keycloak-metrics-spi {};
keycloak-restrict-client-auth = callPackage ./keycloak-restrict-client-auth {};
}

View file

@ -0,0 +1,15 @@
diff --git a/quarkus/dist/src/main/content/bin/kc.sh b/quarkus/dist/src/main/content/bin/kc.sh
index d7be862cde..16f9aa78e0 100644
--- a/bin/kc.sh
+++ b/bin/kc.sh
@@ -32,8 +32,8 @@ abs_path () {
fi
}
-SERVER_OPTS="-Dkc.home.dir='$(abs_path '..')'"
-SERVER_OPTS="$SERVER_OPTS -Djboss.server.config.dir='$(abs_path '../conf')'"
+SERVER_OPTS="-Dkc.home.dir=$KC_HOME_DIR"
+SERVER_OPTS="$SERVER_OPTS -Djboss.server.config.dir=$KC_CONF_DIR"
SERVER_OPTS="$SERVER_OPTS -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
SERVER_OPTS="$SERVER_OPTS -Dquarkus-log-max-startup-records=10000"
CLASSPATH_OPTS="'$(abs_path "../lib/quarkus-run.jar"):$(abs_path "../lib/bootstrap/*")'"

View file

@ -0,0 +1,90 @@
{ stdenv
, lib
, fetchzip
, makeWrapper
, jre
, nixosTests
, callPackage
, confFile ? null
, plugins ? [ ]
, extraFeatures ? [ ]
, disabledFeatures ? [ ]
}:
let
featuresSubcommand = ''
${lib.optionalString (extraFeatures != [ ]) "--features=${lib.concatStringsSep "," extraFeatures}"} \
${lib.optionalString (disabledFeatures != [ ]) "--features-disabled=${lib.concatStringsSep "," disabledFeatures}"}
'';
in stdenv.mkDerivation rec {
pname = "keycloak";
version = "24.0.4";
src = fetchzip {
url = "https://github.com/keycloak/keycloak/releases/download/${version}/keycloak-${version}.zip";
hash = "sha256-tqY3rYFRsRpbvms8DVtCp8nXl0hlX1CzuOVFCE+23o4=";
};
nativeBuildInputs = [ makeWrapper jre ];
patches = [
# Make home.dir and config.dir configurable through the
# KC_HOME_DIR and KC_CONF_DIR environment variables.
./config_vars.patch
];
buildPhase = ''
runHook preBuild
'' + lib.optionalString (confFile != null) ''
install -m 0600 ${confFile} conf/keycloak.conf
'' + ''
install_plugin() {
if [ -d "$1" ]; then
find "$1" -type f \( -iname \*.ear -o -iname \*.jar \) -exec install -m 0500 "{}" "providers/" \;
else
install -m 0500 "$1" "providers/"
fi
}
${lib.concatMapStringsSep "\n" (pl: "install_plugin ${lib.escapeShellArg pl}") plugins}
'' + ''
patchShebangs bin/kc.sh
export KC_HOME_DIR=$(pwd)
export KC_CONF_DIR=$(pwd)/conf
bin/kc.sh build ${featuresSubcommand}
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir $out
cp -r * $out
rm $out/bin/*.{ps1,bat}
runHook postInstall
'';
postFixup = ''
for script in $(find $out/bin -type f -executable); do
wrapProgram "$script" --set JAVA_HOME ${jre} --prefix PATH : ${jre}/bin
done
'';
passthru = {
tests = nixosTests.keycloak;
plugins = callPackage ./all-plugins.nix { };
enabledPlugins = plugins;
};
meta = with lib; {
homepage = "https://www.keycloak.org/";
description = "Identity and access management for modern applications and services";
sourceProvenance = with sourceTypes; [ binaryBytecode ];
license = licenses.asl20;
platforms = jre.meta.platforms;
maintainers = with maintainers; [ ngerstle talyz nickcao ];
};
}

View file

@ -0,0 +1,31 @@
{ stdenv
, lib
, fetchurl
}:
stdenv.mkDerivation rec {
pname = "keycloak-discord";
version = "0.5.0";
src = fetchurl {
url = "https://github.com/wadahiro/keycloak-discord/releases/download/v${version}/keycloak-discord-${version}.jar";
hash = "sha256-radvUu2a6t0lbo5f/ADqy7+I/ONXB7/8pk2d1BtYzQA=";
};
dontUnpack = true;
dontBuild = true;
installPhase = ''
runHook preInstall
install -Dm444 "$src" "$out/keycloak-discord-$version.jar"
runHook postInstall
'';
meta = with lib; {
homepage = "https://github.com/wadahiro/keycloak-discord";
description = "Keycloak Social Login extension for Discord";
license = licenses.asl20;
maintainers = with maintainers; [ mkg20001 ];
sourceProvenance = with sourceTypes; [ binaryBytecode ];
};
}

View file

@ -0,0 +1,33 @@
{ maven, stdenv, lib, fetchFromGitHub }:
maven.buildMavenPackage rec {
pname = "keycloak-metrics-spi";
version = "5.0.0";
src = fetchFromGitHub {
owner = "aerogear";
repo = pname;
rev = "refs/tags/${version}";
hash = "sha256-iagXbsKsU4vNP9eg05bwXEo67iij3N2FF0BW50MjRGE=";
};
mvnHash = {
aarch64-linux = "sha256-zO79pRrY8TqrSK4bB8l4pl6834aFX2pidyk1j9Itz1E=`";
x86_64-linux = "sha256-+ySBrQ9yQ5ZxuVUh/mnHNEmugru3n8x5VR/RYEDCLAo=";
}.${stdenv.hostPlatform.system} or (throw "Unsupported system ${stdenv.hostPlatform.system} for ${pname}");
installPhase = ''
runHook preInstall
install -Dm444 -t "$out" target/keycloak-metrics-spi-*.jar
runHook postInstall
'';
meta = with lib; {
homepage = "https://github.com/aerogear/keycloak-metrics-spi";
description = "Keycloak Service Provider that adds a metrics endpoint";
license = licenses.asl20;
maintainers = with maintainers; [ benley ];
platforms = [ "aarch64-linux" "x86_64-linux" ];
};
}

View file

@ -0,0 +1,28 @@
{ maven, lib, fetchFromGitHub }:
maven.buildMavenPackage rec {
pname = "keycloak-restrict-client-auth";
version = "24.0.0";
src = fetchFromGitHub {
owner = "sventorben";
repo = "keycloak-restrict-client-auth";
rev = "v${version}";
hash = "sha256-Pk0tj8cTHSBwVIzINE7GLA5b/eI97wuOTvO7UoXBStM=";
};
mvnHash = "sha256-Pk2yYuBqGs4k1KwaU06RQe1LpohZu0VI1pHEUBU3EUE=";
installPhase = ''
runHook preInstall
install -Dm444 -t "$out" target/keycloak-restrict-client-auth.jar
runHook postInstall
'';
meta = with lib; {
homepage = "https://github.com/sventorben/keycloak-restrict-client-auth";
description = "A Keycloak authenticator to restrict authorization on clients";
license = licenses.mit;
maintainers = with maintainers; [ leona ];
};
}

View file

@ -0,0 +1,33 @@
{ lib
, fetchFromGitHub
, maven
}:
maven.buildMavenPackage rec {
pname = "scim-for-keycloak";
version = "kc-20-b1"; # When updating also update mvnHash
src = fetchFromGitHub {
owner = "Captain-P-Goldfish";
repo = "scim-for-keycloak";
rev = version;
hash = "sha256-kHjCVkcD8C0tIaMExDlyQmcWMhypisR1nyG93laB8WU=";
};
mvnHash = "sha256-cOuJSU57OuP+U7lI+pDD7g9HPIfZAoDPYLf+eO+XuF4=";
installPhase = ''
install -D "scim-for-keycloak-server/target/scim-for-keycloak-${version}.jar" "$out/scim-for-keycloak-${version}.jar"
'';
meta = with lib; {
homepage = "https://github.com/Captain-P-Goldfish/scim-for-keycloak";
description = "A third party module that extends Keycloak with SCIM functionality";
sourceProvenance = with sourceTypes; [
fromSource
binaryBytecode # dependencies
];
license = licenses.bsd3;
maintainers = with maintainers; [ mkg20001 ];
};
}

View file

@ -0,0 +1,32 @@
{ lib
, fetchFromGitHub
, maven
}:
maven.buildMavenPackage {
pname = "scim-keycloak-user-storage-spi";
version = "unstable-2024-02-14";
src = fetchFromGitHub {
owner = "justin-stephenson";
repo = "scim-keycloak-user-storage-spi";
rev = "6c59915836d9a559983326bbb87f895324bb75e4";
hash = "sha256-BSso9lU542Aroxu0RIX6NARc10lGZ04A/WIWOVtdxHw=";
};
mvnHash = "sha256-xbGlVZl3YtbF372kCDh+UdK5pLe6C6WnGgbEXahlyLw=";
installPhase = ''
install -D "target/scim-user-spi-0.0.1-SNAPSHOT.jar" "$out/scim-user-spi-0.0.1-SNAPSHOT.jar"
'';
meta = with lib; {
homepage = "https://github.com/justin-stephenson/scim-keycloak-user-storage-spi";
description = "A third party module that extends Keycloak, allow for user storage in an external scimv2 server";
sourceProvenance = with sourceTypes; [
fromSource
];
license = licenses.mit;
maintainers = with maintainers; [ s1341 ];
};
}

View file

@ -0,0 +1,66 @@
From 25e5738568b2a021de3a79af3282b2b5feaee9e8 Mon Sep 17 00:00:00 2001
From: Alex Auvolat <alex@adnab.me>
Date: Mon, 12 Feb 2024 10:42:17 +0100
Subject: [PATCH] [fix-secrets-695] take into account rpc secret from file for
cli commands (fix #695)
---
src/garage/main.rs | 23 +++++++++++++++--------
src/garage/secrets.rs | 2 +-
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/src/garage/main.rs b/src/garage/main.rs
index 5c92dae4..1a6a6e32 100644
--- a/src/garage/main.rs
+++ b/src/garage/main.rs
@@ -174,7 +174,9 @@ async fn main() {
}
async fn cli_command(opt: Opt) -> Result<(), Error> {
- let config = if opt.secrets.rpc_secret.is_none() || opt.rpc_host.is_none() {
+ let config = if (opt.secrets.rpc_secret.is_none() && opt.secrets.rpc_secret_file.is_none())
+ || opt.rpc_host.is_none()
+ {
Some(garage_util::config::read_config(opt.config_file.clone())
.err_context(format!("Unable to read configuration file {}. Configuration file is needed because -h or -s is not provided on the command line.", opt.config_file.to_string_lossy()))?)
} else {
@@ -182,14 +184,19 @@ async fn cli_command(opt: Opt) -> Result<(), Error> {
};
// Find and parse network RPC secret
- let net_key_hex_str = opt
- .secrets
- .rpc_secret
- .as_ref()
- .or_else(|| config.as_ref().and_then(|c| c.rpc_secret.as_ref()))
- .ok_or("No RPC secret provided")?;
+ let mut rpc_secret = config.as_ref().and_then(|c| c.rpc_secret.clone());
+ secrets::fill_secret(
+ &mut rpc_secret,
+ &config.as_ref().and_then(|c| c.rpc_secret_file.clone()),
+ &opt.secrets.rpc_secret,
+ &opt.secrets.rpc_secret_file,
+ "rpc_secret",
+ true,
+ )?;
+
+ let net_key_hex_str = rpc_secret.ok_or("No RPC secret provided")?;
let network_key = NetworkKey::from_slice(
- &hex::decode(net_key_hex_str).err_context("Invalid RPC secret key (bad hex)")?[..],
+ &hex::decode(&net_key_hex_str).err_context("Invalid RPC secret key (bad hex)")?[..],
)
.ok_or("Invalid RPC secret provided (wrong length)")?;
diff --git a/src/garage/secrets.rs b/src/garage/secrets.rs
index 8c89a262..a2c64cef 100644
--- a/src/garage/secrets.rs
+++ b/src/garage/secrets.rs
@@ -83,7 +83,7 @@ pub fn fill_secrets(mut config: Config, secrets: Secrets) -> Result<Config, Erro
Ok(config)
}
-fn fill_secret(
+pub(crate) fn fill_secret(
config_secret: &mut Option<String>,
config_secret_file: &Option<String>,
cli_secret: &Option<String>,

View file

@ -1,38 +1,5 @@
diff --git a/src/db/bin/convert.rs b/src/db/bin/convert.rs
index bbde204..7bed4b0 100644
--- a/src/db/bin/convert.rs
+++ b/src/db/bin/convert.rs
@@ -4,6 +4,28 @@ use garage_db::*;
use clap::Parser;
+use std::io::Write;
+
+macro_rules! println {
+ () => (print!("\n"));
+ ($fmt:expr) => ({
+ writeln!(std::io::stdout(), $fmt).unwrap_or(())
+ });
+ ($fmt:expr, $($arg:tt)*) => ({
+ writeln!(std::io::stdout(), $fmt, $($arg)*).unwrap_or(())
+ })
+}
+
+macro_rules! print {
+ () => (print!("\n"));
+ ($fmt:expr) => ({
+ write!(std::io::stdout(), $fmt).unwrap_or(())
+ });
+ ($fmt:expr, $($arg:tt)*) => ({
+ write!(std::io::stdout(), $fmt, $($arg)*).unwrap_or(())
+ })
+}
+
/// K2V command line interface
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
diff --git a/src/db/lib.rs b/src/db/lib.rs
index 11cae4e..ffef3fa 100644
index 11cae4e3..ffef3fac 100644
--- a/src/db/lib.rs
+++ b/src/db/lib.rs
@@ -25,6 +25,18 @@ use std::sync::Arc;
@ -55,7 +22,7 @@ index 11cae4e..ffef3fa 100644
pub struct Db(pub(crate) Arc<dyn IDb>);
diff --git a/src/format-table/lib.rs b/src/format-table/lib.rs
index 55252ba..4d8caf1 100644
index 55252ba9..4d8caf1d 100644
--- a/src/format-table/lib.rs
+++ b/src/format-table/lib.rs
@@ -13,6 +13,18 @@
@ -78,7 +45,7 @@ index 55252ba..4d8caf1 100644
pub fn format_table_to_string(data: Vec<String>) -> String {
let data = data
diff --git a/src/garage/cli/cmd.rs b/src/garage/cli/cmd.rs
index cb7a898..97093e6 100644
index cb7a898c..97093e69 100644
--- a/src/garage/cli/cmd.rs
+++ b/src/garage/cli/cmd.rs
@@ -13,6 +13,28 @@ use garage_model::helper::error::Error as HelperError;
@ -111,7 +78,7 @@ index cb7a898..97093e6 100644
cmd: Command,
system_rpc_endpoint: &Endpoint<SystemRpc, ()>,
diff --git a/src/garage/cli/init.rs b/src/garage/cli/init.rs
index 20813f1..f4baea2 100644
index 20813f1c..f4baea29 100644
--- a/src/garage/cli/init.rs
+++ b/src/garage/cli/init.rs
@@ -2,6 +2,18 @@ use std::path::PathBuf;
@ -134,7 +101,7 @@ index 20813f1..f4baea2 100644
pub fn node_id_command(config_file: PathBuf, quiet: bool) -> Result<(), Error> {
diff --git a/src/garage/cli/layout.rs b/src/garage/cli/layout.rs
index dc5315a..193fd97 100644
index dc5315a1..193fd97c 100644
--- a/src/garage/cli/layout.rs
+++ b/src/garage/cli/layout.rs
@@ -8,6 +8,28 @@ use garage_rpc::*;
@ -167,7 +134,7 @@ index dc5315a..193fd97 100644
cmd: LayoutOperation,
system_rpc_endpoint: &Endpoint<SystemRpc, ()>,
diff --git a/src/garage/cli/util.rs b/src/garage/cli/util.rs
index 1140cf2..e4c4d18 100644
index 1140cf22..e4c4d188 100644
--- a/src/garage/cli/util.rs
+++ b/src/garage/cli/util.rs
@@ -17,6 +17,28 @@ use garage_model::s3::version_table::Version;
@ -200,7 +167,7 @@ index 1140cf2..e4c4d18 100644
println!("List of buckets:");
diff --git a/src/k2v-client/bin/k2v-cli.rs b/src/k2v-client/bin/k2v-cli.rs
index b9461c8..b9cc148 100644
index b9461c89..b9cc1485 100644
--- a/src/k2v-client/bin/k2v-cli.rs
+++ b/src/k2v-client/bin/k2v-cli.rs
@@ -10,6 +10,28 @@ use format_table::format_table;
@ -233,7 +200,7 @@ index b9461c8..b9cc148 100644
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
diff --git a/src/rpc/layout.rs b/src/rpc/layout.rs
index 1030e3a..47eca49 100644
index 1030e3a6..47eca49d 100644
--- a/src/rpc/layout.rs
+++ b/src/rpc/layout.rs
@@ -10,6 +10,28 @@ use garage_util::error::*;

View file

@ -1,17 +0,0 @@
diff --git a/Jellyfin.Api/Models/StreamingDtos/StreamState.cs b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs
index 192f33e..fd6672b 100644
--- a/Jellyfin.Api/Models/StreamingDtos/StreamState.cs
+++ b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs
@@ -100,10 +100,10 @@ namespace Jellyfin.Api.Models.StreamingDtos
return 3;
}
- return 6;
+ return 9;
}
- return 3;
+ return 6;
}
}