Merge branch 'master' into deploy-machine-ssh-key
This commit is contained in:
commit
670cecbebf
|
@ -8,10 +8,9 @@ jobs:
|
|||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v1
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 15.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
|
@ -22,24 +21,27 @@ jobs:
|
|||
- name: "Static code analysis: health-check"
|
||||
run: yarn workspace health-check prettier --check .
|
||||
|
||||
- name: "Static code analysis: webapp"
|
||||
run: yarn workspace webapp prettier --check .
|
||||
- name: "Static code analysis: website"
|
||||
run: yarn workspace website prettier --check .
|
||||
|
||||
- name: "Build webapp"
|
||||
run: yarn workspace webapp build
|
||||
env:
|
||||
GATSBY_API_URL: "https://siasky.net"
|
||||
- name: "Static code analysis: dashboard"
|
||||
run: yarn workspace dashboard prettier --check .
|
||||
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@v2
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
working-directory: packages/webapp
|
||||
record: true
|
||||
start: npx http-server public --port 8000
|
||||
wait-on: "http://localhost:8000"
|
||||
# - name: "Build webapp"
|
||||
# run: yarn workspace webapp build
|
||||
# env:
|
||||
# GATSBY_API_URL: "https://siasky.net"
|
||||
|
||||
- name: Cypress cache prune
|
||||
run: yarn cypress cache prune
|
||||
# - name: Cypress run
|
||||
# uses: cypress-io/github-action@v2
|
||||
# env:
|
||||
# CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# with:
|
||||
# working-directory: packages/webapp
|
||||
# record: true
|
||||
# start: npx http-server public --port 8000
|
||||
# wait-on: "http://localhost:8000"
|
||||
|
||||
# - name: Cypress cache prune
|
||||
# run: yarn cypress cache prune
|
||||
|
|
|
@ -15,6 +15,10 @@ services:
|
|||
depends_on:
|
||||
- accounts
|
||||
|
||||
health-check:
|
||||
environment:
|
||||
- ACCOUNTS_ENABLED=1
|
||||
|
||||
accounts:
|
||||
build:
|
||||
context: ./docker/accounts
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
version: '3.7'
|
||||
|
||||
services:
|
||||
sia:
|
||||
environment:
|
||||
- JAEGER_DISABLED=${JAEGER_DISABLED:-true} # Enable/Disable tracing
|
||||
- JAEGER_SERVICE_NAME=${PORTAL_NAME:-Skyd} # change to e.g. eu-ger-1
|
||||
# Configuration
|
||||
# See https://github.com/jaegertracing/jaeger-client-go#environment-variables
|
||||
# for all options.
|
||||
- JAEGER_SAMPLER_TYPE=probabilistic
|
||||
- JAEGER_SAMPLER_PARAM=0.1
|
||||
- JAEGER_AGENT_HOST=jaeger-agent
|
||||
- JAEGER_AGENT_PORT=6831
|
||||
- JAEGER_REPORTER_LOG_SPANS=false
|
||||
|
||||
jaeger-agent:
|
||||
image: jaegertracing/jaeger-agent
|
||||
command: [ "--reporter.grpc.host-port=jaeger-collector:14250", "--reporter.grpc.retry.max=1000" ]
|
||||
container_name: jaeger-agent
|
||||
restart: on-failure
|
||||
expose:
|
||||
- 6831
|
||||
- 6832
|
||||
- 5778
|
||||
environment:
|
||||
- LOG_LEVEL=debug
|
||||
networks:
|
||||
shared:
|
||||
ipv4_address: 10.10.10.90
|
||||
depends_on:
|
||||
- jaeger-collector
|
||||
|
||||
jaeger-collector:
|
||||
image: jaegertracing/jaeger-collector
|
||||
entrypoint: /wait_to_start.sh
|
||||
container_name: jaeger-collector
|
||||
restart: on-failure
|
||||
expose:
|
||||
- 14269
|
||||
- 14268
|
||||
- 14250
|
||||
environment:
|
||||
- SPAN_STORAGE_TYPE=elasticsearch
|
||||
- LOG_LEVEL=debug
|
||||
- WAIT_START_CMD=/go/bin/collector-linux --es.num-shards=1 --es.num-replicas=0 --es.server-urls=http://elasticsearch:9200
|
||||
- WAIT_COMMAND=wget -qO index.html http://elasticsearch:9200
|
||||
- WAIT_SLEEP=1
|
||||
- WAIT_LOOPS=600
|
||||
volumes:
|
||||
- ./scripts/wait_to_start.sh:/wait_to_start.sh:ro
|
||||
networks:
|
||||
shared:
|
||||
ipv4_address: 10.10.10.91
|
||||
depends_on:
|
||||
- elasticsearch
|
||||
|
||||
jaeger-query:
|
||||
image: jaegertracing/jaeger-query
|
||||
entrypoint: /wait_to_start.sh
|
||||
container_name: jaeger-query
|
||||
restart: on-failure
|
||||
ports:
|
||||
- "127.0.0.1:16686:16686"
|
||||
expose:
|
||||
- 16687
|
||||
environment:
|
||||
- SPAN_STORAGE_TYPE=elasticsearch
|
||||
- LOG_LEVEL=debug
|
||||
- WAIT_START_CMD=/go/bin/query-linux --es.num-shards=1 --es.num-replicas=0 --es.server-urls=http://elasticsearch:9200
|
||||
- WAIT_COMMAND=wget -qO index.html http://elasticsearch:9200
|
||||
- WAIT_SLEEP=1
|
||||
- WAIT_LOOPS=600
|
||||
volumes:
|
||||
- ./scripts/wait_to_start.sh:/wait_to_start.sh:ro
|
||||
networks:
|
||||
shared:
|
||||
ipv4_address: 10.10.10.92
|
||||
depends_on:
|
||||
- elasticsearch
|
||||
|
||||
elasticsearch:
|
||||
image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.8.15
|
||||
container_name: elasticsearch
|
||||
restart: on-failure
|
||||
environment:
|
||||
- discovery.type=single-node
|
||||
volumes:
|
||||
# This dir needs to be chowned to 1000:1000
|
||||
- ./docker/data/elasticsearch/data:/usr/share/elasticsearch/data
|
||||
ports:
|
||||
# We need to expose this port, so we can prune the indexes.
|
||||
- "127.0.0.1:9200:9200"
|
||||
networks:
|
||||
shared:
|
||||
ipv4_address: 10.10.10.93
|
|
@ -80,7 +80,6 @@ services:
|
|||
- 80
|
||||
depends_on:
|
||||
- sia
|
||||
- health-check
|
||||
- handshake-api
|
||||
- website
|
||||
|
||||
|
@ -155,12 +154,12 @@ services:
|
|||
networks:
|
||||
shared:
|
||||
ipv4_address: 10.10.10.60
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- HOSTNAME=0.0.0.0
|
||||
- PORTAL_URL=http://nginx
|
||||
- STATE_DIR=/usr/app/state
|
||||
expose:
|
||||
- 3100
|
||||
depends_on:
|
||||
- handshake
|
||||
- handshake-api
|
||||
- caddy
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
preserve_host: true
|
||||
url: "http://accounts:3000"
|
||||
match:
|
||||
url: "http://oathkeeper<{,:4455}>/<{stripe/prices,stripe/webhook}>"
|
||||
url: "http://oathkeeper<{,:4455}>/<{health,stripe/prices,stripe/webhook}>"
|
||||
methods:
|
||||
- GET
|
||||
- POST
|
||||
|
|
|
@ -72,23 +72,23 @@ server {
|
|||
rewrite ^/skynet/blacklist /skynet/blocklist permanent;
|
||||
rewrite ^/account/(.*) https://account.$domain.$tld/$1 permanent;
|
||||
|
||||
# This is only safe workaround to reroute based on some conditions
|
||||
# See https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/
|
||||
recursive_error_pages on;
|
||||
|
||||
# redirect links with base32 encoded skylink in subdomain
|
||||
error_page 460 = @base32_subdomain;
|
||||
if ($base32_subdomain != "") {
|
||||
return 460;
|
||||
}
|
||||
|
||||
# redirect links with handshake domain on hns subdomain
|
||||
error_page 461 = @hns_domain;
|
||||
if ($hns_domain != "") {
|
||||
return 461;
|
||||
}
|
||||
|
||||
location / {
|
||||
# This is only safe workaround to reroute based on some conditions
|
||||
# See https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/
|
||||
recursive_error_pages on;
|
||||
|
||||
# redirect links with base32 encoded skylink in subdomain
|
||||
error_page 460 = @base32_subdomain;
|
||||
if ($base32_subdomain != "") {
|
||||
return 460;
|
||||
}
|
||||
|
||||
# redirect links with handshake domain on hns subdomain
|
||||
error_page 461 = @hns_domain;
|
||||
if ($hns_domain != "") {
|
||||
return 461;
|
||||
}
|
||||
|
||||
include /etc/nginx/conf.d/include/cors;
|
||||
|
||||
proxy_pass http://website:9000;
|
||||
|
@ -147,7 +147,7 @@ server {
|
|||
}
|
||||
|
||||
proxy_cache skynet;
|
||||
proxy_cache_valid any 10m; # cache stats for 10 minutes
|
||||
proxy_cache_valid any 1m; # cache stats for 1 minute
|
||||
proxy_set_header User-Agent: Sia-Agent;
|
||||
proxy_read_timeout 5m; # extend the read timeout
|
||||
proxy_pass http://siad/skynet/stats;
|
||||
|
@ -399,6 +399,13 @@ server {
|
|||
proxy_pass http://siad;
|
||||
}
|
||||
|
||||
location /skynet/metadata {
|
||||
include /etc/nginx/conf.d/include/cors;
|
||||
|
||||
proxy_set_header User-Agent: Sia-Agent;
|
||||
proxy_pass http://siad;
|
||||
}
|
||||
|
||||
location ~ "^/(([a-zA-Z0-9-_]{46}|[a-z0-9]{55})(/.*)?)$" {
|
||||
include /etc/nginx/conf.d/include/cors;
|
||||
include /etc/nginx/conf.d/include/proxy-buffer;
|
||||
|
|
|
@ -8,36 +8,32 @@
|
|||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/metropolis": "^4.1.0",
|
||||
"@ory/kratos-client": "^0.5.4-alpha.1",
|
||||
"@stripe/react-stripe-js": "^1.4.0",
|
||||
"@stripe/stripe-js": "^1.13.0",
|
||||
"@tailwindcss/forms": "^0.2.1",
|
||||
"autoprefixer": "^10.2.5",
|
||||
"classnames": "^2.2.6",
|
||||
"clipboardy": "^2.3.0",
|
||||
"dayjs": "^1.10.4",
|
||||
"express-jwt": "^6.0.0",
|
||||
"fast-levenshtein": "^3.0.0",
|
||||
"formik": "^2.2.6",
|
||||
"http-status-codes": "^2.1.4",
|
||||
"jwks-rsa": "^1.12.2",
|
||||
"@fontsource/metropolis": "4.3.0",
|
||||
"@ory/kratos-client": "0.5.4-alpha.1",
|
||||
"@stripe/react-stripe-js": "1.4.0",
|
||||
"@stripe/stripe-js": "1.14.0",
|
||||
"@tailwindcss/forms": "0.3.2",
|
||||
"autoprefixer": "10.2.5",
|
||||
"classnames": "2.3.1",
|
||||
"clipboardy": "2.3.0",
|
||||
"dayjs": "1.10.4",
|
||||
"express-jwt": "6.0.0",
|
||||
"fast-levenshtein": "3.0.0",
|
||||
"formik": "2.2.6",
|
||||
"http-status-codes": "2.1.4",
|
||||
"ky": "0.25.1",
|
||||
"next": "^10.0.8",
|
||||
"postcss": "^8.2.8",
|
||||
"prettier": "^2.2.1",
|
||||
"pretty-bytes": "^5.5.0",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1",
|
||||
"skynet-js": "^3.0.0",
|
||||
"square": "^9.0.0",
|
||||
"stripe": "^8.137.0",
|
||||
"superagent": "^6.1.0",
|
||||
"swr": "^0.5.0",
|
||||
"tailwindcss": "^2.0.3",
|
||||
"yup": "^0.32.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/forms": "^0.2.1"
|
||||
"next": "10.2.0",
|
||||
"postcss": "8.2.14",
|
||||
"prettier": "2.3.0",
|
||||
"pretty-bytes": "5.6.0",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"skynet-js": "3.0.2",
|
||||
"square": "10.0.0",
|
||||
"stripe": "8.148.0",
|
||||
"superagent": "6.1.0",
|
||||
"swr": "0.5.6",
|
||||
"tailwindcss": "2.1.2",
|
||||
"yup": "0.32.9"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,7 +200,9 @@ export default function Home({ plans }) {
|
|||
<div className="ml-5 w-0 flex-1">
|
||||
<dt className="text-sm font-medium text-gray-500 truncate">Storage used</dt>
|
||||
<dd className="flex items-baseline">
|
||||
<div className="text-2xl font-semibold text-grey-900">{prettyBytes(stats?.totalUploadsSize ?? 0)}</div>
|
||||
<div className="text-2xl font-semibold text-grey-900">
|
||||
{prettyBytes(stats?.totalUploadsSize ?? 0)}
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,4 +12,4 @@ RUN echo '0 * * * * /usr/app/cli/run extended > /dev/stdout' >> /etc/crontabs/ro
|
|||
|
||||
EXPOSE 3100
|
||||
ENV NODE_ENV production
|
||||
CMD [ "sh", "-c", "crond ; node --max-http-header-size=64000 src/index.js" ]
|
||||
CMD [ "sh", "-c", "crond ; echo $(node src/whatismyip.js) siasky.net account.siasky.net >> /etc/hosts ; node --max-http-header-size=64000 src/index.js" ]
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"dependencies": {
|
||||
"deep-object-diff": "^1.1.0",
|
||||
"express": "^4.17.1",
|
||||
"form-data": "^3.0.1",
|
||||
"form-data": "^4.0.0",
|
||||
"got": "^11.8.2",
|
||||
"graceful-fs": "^4.2.6",
|
||||
"hasha": "^5.2.2",
|
||||
|
@ -14,7 +14,7 @@
|
|||
"lodash": "^4.17.21",
|
||||
"lowdb": "^1.0.0",
|
||||
"write-file-atomic": "^3.0.3",
|
||||
"yargs": "^16.2.0"
|
||||
"yargs": "^17.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^2.2.1"
|
||||
|
|
|
@ -7,26 +7,28 @@ const { calculateElapsedTime, getResponseContent } = require("../utils");
|
|||
async function uploadCheck(done) {
|
||||
const time = process.hrtime();
|
||||
const form = new FormData();
|
||||
const data = Buffer.from(new Date()); // current date to ensure data uniqueness
|
||||
const payload = Buffer.from(new Date()); // current date to ensure data uniqueness
|
||||
const data = { up: false };
|
||||
|
||||
form.append("file", data, { filename: "time.txt", contentType: "text/plain" });
|
||||
let statusCode, errorResponseContent;
|
||||
form.append("file", payload, { filename: "time.txt", contentType: "text/plain" });
|
||||
|
||||
try {
|
||||
const response = await got.post(`${process.env.PORTAL_URL}/skynet/skyfile`, { body: form });
|
||||
const response = await got.post(`${process.env.SKYNET_PORTAL_API}/skynet/skyfile`, { body: form });
|
||||
|
||||
statusCode = response.statusCode;
|
||||
data.statusCode = response.statusCode;
|
||||
data.up = true;
|
||||
data.ip = response.ip;
|
||||
} catch (error) {
|
||||
statusCode = error?.response?.statusCode || error.statusCode || error.status;
|
||||
errorResponseContent = getResponseContent(error?.response);
|
||||
data.statusCode = error.response?.statusCode || error.statusCode || error.status;
|
||||
data.errorMessage = error.message;
|
||||
data.errorResponseContent = getResponseContent(error.response);
|
||||
data.ip = error?.response?.ip ?? null;
|
||||
}
|
||||
|
||||
done({
|
||||
name: "upload_file",
|
||||
up: statusCode === StatusCodes.OK,
|
||||
statusCode,
|
||||
errorResponseContent,
|
||||
time: calculateElapsedTime(time),
|
||||
...data,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -34,26 +36,57 @@ async function uploadCheck(done) {
|
|||
async function downloadCheck(done) {
|
||||
const time = process.hrtime();
|
||||
const skylink = "AACogzrAimYPG42tDOKhS3lXZD8YvlF8Q8R17afe95iV2Q";
|
||||
let statusCode, errorMessage, errorResponseContent;
|
||||
const data = { up: false };
|
||||
|
||||
try {
|
||||
const response = await got(`${process.env.PORTAL_URL}/${skylink}?nocache=true`);
|
||||
const response = await got(`${process.env.SKYNET_PORTAL_API}/${skylink}?nocache=true`);
|
||||
|
||||
statusCode = response.statusCode;
|
||||
data.statusCode = response.statusCode;
|
||||
data.up = true;
|
||||
data.ip = response.ip;
|
||||
} catch (error) {
|
||||
statusCode = error?.response?.statusCode || error.statusCode || error.status;
|
||||
errorMessage = error.message;
|
||||
errorResponseContent = getResponseContent(error.response);
|
||||
data.statusCode = error?.response?.statusCode || error.statusCode || error.status;
|
||||
data.errorMessage = error.message;
|
||||
data.errorResponseContent = getResponseContent(error.response);
|
||||
data.ip = error?.response?.ip ?? null;
|
||||
}
|
||||
|
||||
done({
|
||||
name: "download_file",
|
||||
up: statusCode === StatusCodes.OK,
|
||||
statusCode,
|
||||
errorMessage,
|
||||
errorResponseContent,
|
||||
time: calculateElapsedTime(time),
|
||||
...data,
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = [uploadCheck, downloadCheck];
|
||||
async function accountHealthCheck(done) {
|
||||
const time = process.hrtime();
|
||||
const data = { up: false };
|
||||
|
||||
try {
|
||||
const response = await got(`${process.env.SKYNET_DASHBOARD_URL}/health`, { responseType: "json" });
|
||||
|
||||
data.statusCode = response.statusCode;
|
||||
data.response = response.body;
|
||||
data.up = response.body.dbAlive === true;
|
||||
data.ip = response.ip;
|
||||
} catch (error) {
|
||||
data.statusCode = error?.response?.statusCode || error.statusCode || error.status;
|
||||
data.errorMessage = error.message;
|
||||
data.errorResponseContent = getResponseContent(error.response);
|
||||
data.ip = error?.response?.ip ?? null;
|
||||
}
|
||||
|
||||
done({
|
||||
name: "account_health",
|
||||
time: calculateElapsedTime(time),
|
||||
...data,
|
||||
});
|
||||
}
|
||||
|
||||
const checks = [uploadCheck, downloadCheck];
|
||||
|
||||
if (process.env.ACCOUNTS_ENABLED) {
|
||||
checks.push(accountHealthCheck);
|
||||
}
|
||||
|
||||
module.exports = checks;
|
||||
|
|
|
@ -1059,7 +1059,7 @@ async function skylinkVerification(done, expected, { followRedirect = true, meth
|
|||
const details = { name: expected.name, skylink: expected.skylink };
|
||||
|
||||
try {
|
||||
const query = `${process.env.PORTAL_URL}/${expected.skylink}`;
|
||||
const query = `${process.env.SKYNET_PORTAL_API}/${expected.skylink}`;
|
||||
const response = await got[method](query, { followRedirect, headers: { cookie: "nocache=true" } });
|
||||
const entry = { ...details, up: true, statusCode: response.statusCode, time: calculateElapsedTime(time) };
|
||||
const info = {};
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
process.env.NODE_ENV = process.env.NODE_ENV || "development";
|
||||
|
||||
if (!process.env.PORTAL_URL) {
|
||||
throw new Error("You need to provide PORTAL_URL environment variable");
|
||||
if (!process.env.SKYNET_PORTAL_API) {
|
||||
throw new Error("You need to provide SKYNET_PORTAL_API environment variable");
|
||||
}
|
||||
|
||||
if (process.env.ACCOUNTS_ENABLED && !process.env.SKYNET_DASHBOARD_URL) {
|
||||
throw new Error("You need to provide SKYNET_DASHBOARD_URL environment variable when accounts are enabled");
|
||||
}
|
||||
|
||||
const express = require("express");
|
||||
|
|
|
@ -12,7 +12,7 @@ require("yargs/yargs")(process.argv.slice(2)).command(
|
|||
})
|
||||
.option("portal-url", {
|
||||
describe: "Skynet portal url",
|
||||
default: process.env.PORTAL_URL || "https://siasky.net",
|
||||
default: process.env.SKYNET_PORTAL_API || "https://siasky.net",
|
||||
type: "string",
|
||||
})
|
||||
.option("state-dir", {
|
||||
|
@ -22,7 +22,7 @@ require("yargs/yargs")(process.argv.slice(2)).command(
|
|||
});
|
||||
},
|
||||
async ({ type, portalUrl, stateDir }) => {
|
||||
process.env.PORTAL_URL = portalUrl;
|
||||
process.env.SKYNET_PORTAL_API = portalUrl;
|
||||
process.env.STATE_DIR = stateDir;
|
||||
|
||||
const db = require("../src/db");
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
const http = require("http");
|
||||
|
||||
const request = http.request({ host: "whatismyip.akamai.com" }, (response) => {
|
||||
response.on("data", (data) => {
|
||||
process.stdout.write(data);
|
||||
});
|
||||
});
|
||||
|
||||
request.on("error", (error) => {
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
request.end();
|
|
@ -8,13 +8,13 @@
|
|||
"axios": "0.21.1",
|
||||
"boolean": "^3.0.2",
|
||||
"bytes": "3.1.0",
|
||||
"classnames": "2.2.6",
|
||||
"classnames": "2.3.1",
|
||||
"gatsby": "^3.0.4",
|
||||
"gatsby-plugin-manifest": "^3.0.0",
|
||||
"gatsby-plugin-matomo": "0.9.0",
|
||||
"gatsby-plugin-react-helmet": "^4.0.0",
|
||||
"gatsby-plugin-remove-serviceworker": "1.0.0",
|
||||
"gatsby-plugin-robots-txt": "1.5.5",
|
||||
"gatsby-plugin-robots-txt": "1.5.6",
|
||||
"gatsby-plugin-sass": "^4.0.2",
|
||||
"gatsby-source-filesystem": "^3.0.0",
|
||||
"http-status-codes": "2.1.4",
|
||||
|
@ -26,21 +26,21 @@
|
|||
"react": "17.0.1",
|
||||
"react-countup": "4.3.3",
|
||||
"react-dom": "17.0.1",
|
||||
"react-dropzone": "11.3.1",
|
||||
"react-dropzone": "11.3.2",
|
||||
"react-helmet": "6.1.0",
|
||||
"react-mailchimp-form": "1.0.2",
|
||||
"react-mailchimp-subscribe": "^2.1.3",
|
||||
"react-syntax-highlighter": "15.4.3",
|
||||
"react-visibility-sensor": "5.1.1",
|
||||
"skynet-js": "3.0.0"
|
||||
"skynet-js": "3.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cypress": "^6.6.0",
|
||||
"cypress-file-upload": "5.0.3",
|
||||
"eslint": "7.22.0",
|
||||
"eslint-config-prettier": "8.1.0",
|
||||
"cypress": "^7.1.0",
|
||||
"cypress-file-upload": "5.0.7",
|
||||
"eslint": "7.26.0",
|
||||
"eslint-config-prettier": "8.2.0",
|
||||
"eslint-plugin-cypress": "2.11.2",
|
||||
"eslint-plugin-react": "7.23.0",
|
||||
"eslint-plugin-react": "7.23.2",
|
||||
"husky": "4.3.8",
|
||||
"lint-staged": "10.5.4",
|
||||
"prettier": "2.2.1"
|
||||
|
|
|
@ -19,4 +19,4 @@
|
|||
module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
import "./commands";
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const { defaultIcons } = require("gatsby-plugin-manifest/common");
|
||||
|
||||
module.exports = {
|
||||
flags: { PRESERVE_WEBPACK_CACHE: true },
|
||||
siteMetadata: {
|
||||
title: `Skynet`,
|
||||
description: `Skynet is a decentralized file sharing and content distribution protocol`,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,8 +5,8 @@
|
|||
"version": "0.1.0",
|
||||
"author": "Skynet Labs.",
|
||||
"dependencies": {
|
||||
"@fontsource/sora": "^4.2.2",
|
||||
"@fontsource/source-sans-pro": "^4.2.2",
|
||||
"@fontsource/sora": "^4.3.0",
|
||||
"@fontsource/source-sans-pro": "^4.3.0",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"@tailwindcss/typography": "^0.4.0",
|
||||
"autoprefixer": "^10.2.5",
|
||||
|
@ -14,40 +14,40 @@
|
|||
"classnames": "^2.3.1",
|
||||
"copy-text-to-clipboard": "^3.0.1",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"framer-motion": "^4.0.3",
|
||||
"gatsby": "^3.2.1",
|
||||
"gatsby-background-image": "^1.5.0",
|
||||
"gatsby-image": "^3.2.0",
|
||||
"gatsby-plugin-image": "^1.1.2",
|
||||
"gatsby-plugin-manifest": "^3.0.0",
|
||||
"framer-motion": "^4.1.15",
|
||||
"gatsby": "^3.4.2",
|
||||
"gatsby-background-image": "^1.5.3",
|
||||
"gatsby-image": "^3.4.0",
|
||||
"gatsby-plugin-image": "^1.4.1",
|
||||
"gatsby-plugin-manifest": "^3.4.0",
|
||||
"gatsby-plugin-matomo": "^0.9.0",
|
||||
"gatsby-plugin-offline": "^4.0.0",
|
||||
"gatsby-plugin-postcss": "^4.0.0",
|
||||
"gatsby-plugin-offline": "^4.4.0",
|
||||
"gatsby-plugin-postcss": "^4.4.0",
|
||||
"gatsby-plugin-purgecss": "^6.0.0",
|
||||
"gatsby-plugin-react-helmet": "^4.0.0",
|
||||
"gatsby-plugin-react-helmet": "^4.4.0",
|
||||
"gatsby-plugin-react-svg": "^3.0.0",
|
||||
"gatsby-plugin-robots-txt": "^1.5.5",
|
||||
"gatsby-plugin-sharp": "^3.1.2",
|
||||
"gatsby-plugin-robots-txt": "^1.6.2",
|
||||
"gatsby-plugin-sharp": "^3.4.2",
|
||||
"gatsby-remark-classes": "^1.0.0",
|
||||
"gatsby-remark-copy-linked-files": "^4.0.0",
|
||||
"gatsby-remark-images": "^5.0.0",
|
||||
"gatsby-remark-prismjs": "^5.0.0",
|
||||
"gatsby-remark-responsive-iframe": "^4.0.0",
|
||||
"gatsby-remark-smartypants": "^4.0.0",
|
||||
"gatsby-source-filesystem": "^3.0.0",
|
||||
"gatsby-transformer-json": "^3.1.0",
|
||||
"gatsby-transformer-remark": "^4.0.0",
|
||||
"gatsby-transformer-sharp": "^3.0.0",
|
||||
"gatsby-transformer-yaml": "^3.2.0",
|
||||
"gbimage-bridge": "^0.1.1",
|
||||
"gatsby-remark-copy-linked-files": "^4.1.0",
|
||||
"gatsby-remark-images": "^5.1.0",
|
||||
"gatsby-remark-prismjs": "^5.1.0",
|
||||
"gatsby-remark-responsive-iframe": "^4.1.0",
|
||||
"gatsby-remark-smartypants": "^4.1.0",
|
||||
"gatsby-source-filesystem": "^3.4.0",
|
||||
"gatsby-transformer-json": "^3.4.0",
|
||||
"gatsby-transformer-remark": "^4.1.0",
|
||||
"gatsby-transformer-sharp": "^3.4.0",
|
||||
"gatsby-transformer-yaml": "^3.4.0",
|
||||
"gbimage-bridge": "^0.1.4",
|
||||
"http-status-codes": "^2.1.4",
|
||||
"jsonp": "^0.2.1",
|
||||
"ms": "^2.1.2",
|
||||
"normalize.css": "^8.0.1",
|
||||
"path-browserify": "^1.0.1",
|
||||
"polished": "^4.1.1",
|
||||
"polished": "^4.1.2",
|
||||
"popmotion": "^9.3.4",
|
||||
"postcss": "^8.2.8",
|
||||
"postcss": "^8.2.15",
|
||||
"preact-svg-loader": "^0.2.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^17.0.2",
|
||||
|
@ -57,17 +57,17 @@
|
|||
"react-share": "^4.4.0",
|
||||
"react-svg-loader": "^3.0.3",
|
||||
"react-syntax-highlighter": "^15.4.3",
|
||||
"react-use": "^17.2.3",
|
||||
"react-use": "^17.2.4",
|
||||
"skynet-js": "^3.0.2",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"swr": "^0.5.5",
|
||||
"tailwindcss": "^2.1.1"
|
||||
"swr": "^0.5.6",
|
||||
"tailwindcss": "^2.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^7.0.3",
|
||||
"cypress": "^7.1.0",
|
||||
"cypress-file-upload": "^5.0.5",
|
||||
"prettier": "^2.2.1"
|
||||
"cypress": "^7.3.0",
|
||||
"cypress-file-upload": "^5.0.7",
|
||||
"prettier": "^2.3.0"
|
||||
},
|
||||
"keywords": [
|
||||
"gatsby"
|
||||
|
|
|
@ -24,40 +24,34 @@ const aboutCards = [
|
|||
{
|
||||
Icon: UserAtom,
|
||||
title: "Own your data",
|
||||
text:
|
||||
"No one owns or controls your account data except for you. Ownership extends to original blogs, music, and videos too. This is all possible through decentralized apps built on decentralized storage.",
|
||||
text: "No one owns or controls your account data except for you. Ownership extends to original blogs, music, and videos too. This is all possible through decentralized apps built on decentralized storage.",
|
||||
},
|
||||
{
|
||||
Icon: Shield,
|
||||
title: "Censorship-resistant content",
|
||||
text:
|
||||
"Today, censorship can come arbitrarily, top-down, and as a tool to silence expression. Post and share content on Skynet, or use Skynet as a fail-over for your website if a service provider goes down.",
|
||||
text: "Today, censorship can come arbitrarily, top-down, and as a tool to silence expression. Post and share content on Skynet, or use Skynet as a fail-over for your website if a service provider goes down.",
|
||||
},
|
||||
{
|
||||
Icon: Fingerprint,
|
||||
title: "One universal digital identity",
|
||||
text:
|
||||
"Log into any Skynet app with just one ID. Once logged in, your storage and data can follow you across the ecosystem. Access your friend lists, followers, and content from any Skynet app.",
|
||||
text: "Log into any Skynet app with just one ID. Once logged in, your storage and data can follow you across the ecosystem. Access your friend lists, followers, and content from any Skynet app.",
|
||||
},
|
||||
{
|
||||
Icon: UserArrows,
|
||||
title: "Innovation built for users",
|
||||
text:
|
||||
"All Skynet apps are open-source. If you dislike an app’s feature or want to make your own improvements, you’re welcome to do so. (We of course encourage collaboration and hope you chat with the developer first!) Existing users can then consent to the migration of all their account data to the latest version. ",
|
||||
text: "All Skynet apps are open-source. If you dislike an app’s feature or want to make your own improvements, you’re welcome to do so. (We of course encourage collaboration and hope you chat with the developer first!) Existing users can then consent to the migration of all their account data to the latest version. ",
|
||||
},
|
||||
{
|
||||
Icon: ComputerScreen,
|
||||
label: "Coming soon",
|
||||
title: "Control your content feed",
|
||||
text:
|
||||
"We believe that users, not tech platforms should fully control how content is moderated. A decentralized internet is not an information free-for-all. It means that the individual holds the power to personalize their online experiences. For example, users will decide what content appears in their social media feeds, not a corporate algorithm.",
|
||||
text: "We believe that users, not tech platforms should fully control how content is moderated. A decentralized internet is not an information free-for-all. It means that the individual holds the power to personalize their online experiences. For example, users will decide what content appears in their social media feeds, not a corporate algorithm.",
|
||||
},
|
||||
{
|
||||
Icon: Cogs,
|
||||
label: "Coming soon",
|
||||
title: "Developer and Creator-centric monetization",
|
||||
text:
|
||||
"As a content creator, set your own terms and price for your art. You and your collaborators can get paid directly, fairly, and automatically in crypto without relying on advertising as a sole source of income.",
|
||||
text: "As a content creator, set your own terms and price for your art. You and your collaborators can get paid directly, fairly, and automatically in crypto without relying on advertising as a sole source of income.",
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -19,32 +19,27 @@ const reasonCards = [
|
|||
{
|
||||
Icon: DataSwap,
|
||||
title: "Immutable Data, Globally Available & Trustless",
|
||||
text:
|
||||
"Our immutable data layer means files are instantly accessible on any device, by any portal and are fully verifiable, by leveraging trustless, decentralized storage on the Sia blockchain.",
|
||||
text: "Our immutable data layer means files are instantly accessible on any device, by any portal and are fully verifiable, by leveraging trustless, decentralized storage on the Sia blockchain.",
|
||||
},
|
||||
{
|
||||
Icon: Encryption,
|
||||
title: "Dynamic Content with a User-Focus",
|
||||
text:
|
||||
"SkyDB enables complex apps by providing a key-value store for mutable data secured by the private key of the user.",
|
||||
text: "SkyDB enables complex apps by providing a key-value store for mutable data secured by the private key of the user.",
|
||||
},
|
||||
{
|
||||
Icon: Layers,
|
||||
title: "BYO Frontend Library",
|
||||
text:
|
||||
"Our SDKs are built with web2 developers in mind. Client-side web apps and static generators are perfect for using Skynet to deploy with.",
|
||||
text: "Our SDKs are built with web2 developers in mind. Client-side web apps and static generators are perfect for using Skynet to deploy with.",
|
||||
},
|
||||
{
|
||||
Icon: Mesh,
|
||||
title: "Decentralized Stack-Friendly",
|
||||
text:
|
||||
"With integrations with HNS & ENS, along with easy-access for off-chain storage, Skynet is positioned to connect with the DWeb and web3 technologies you need.",
|
||||
text: "With integrations with HNS & ENS, along with easy-access for off-chain storage, Skynet is positioned to connect with the DWeb and web3 technologies you need.",
|
||||
},
|
||||
{
|
||||
Icon: Toolkit,
|
||||
title: "Hack Today & Activate an Existing User Base",
|
||||
text:
|
||||
"Start building without worrying about server overhead costs or where users will come from. Bootstrap the user experience with interoperable storage and user-identity – right out of the box.",
|
||||
text: "Start building without worrying about server overhead costs or where users will come from. Bootstrap the user experience with interoperable storage and user-identity – right out of the box.",
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -36,32 +36,27 @@ const ecosystemCards = [
|
|||
{
|
||||
Icon: SkynetUsageSmall,
|
||||
title: "Easy to use",
|
||||
text:
|
||||
"Decentralized storage without needing to run a node or wallet. Skynet also includes SDKs for popular programming languages and APIs that integrate seamlessly with your existing apps.",
|
||||
text: "Decentralized storage without needing to run a node or wallet. Skynet also includes SDKs for popular programming languages and APIs that integrate seamlessly with your existing apps.",
|
||||
},
|
||||
{
|
||||
Icon: SkynetSpeedSmall,
|
||||
title: "Fast",
|
||||
text:
|
||||
"Skynet's speeds rival centralized providers and surpass all decentralized offerings. A typical Skynet download starts in under 500 ms and can stream at rates as high as 1 Gbps!",
|
||||
text: "Skynet's speeds rival centralized providers and surpass all decentralized offerings. A typical Skynet download starts in under 500 ms and can stream at rates as high as 1 Gbps!",
|
||||
},
|
||||
{
|
||||
Icon: SkynetSiaSmall,
|
||||
title: "Free to use",
|
||||
text:
|
||||
"Focus on building, not overhead server costs. When users own their data, developers aren't asked to pay for it.",
|
||||
text: "Focus on building, not overhead server costs. When users own their data, developers aren't asked to pay for it.",
|
||||
},
|
||||
{
|
||||
Icon: SkynetMonetizationSmall,
|
||||
title: "Monetization",
|
||||
text:
|
||||
"Profit directly from the success of your skapp. Now you can truly prioritize your users, instead of advertisers.",
|
||||
text: "Profit directly from the success of your skapp. Now you can truly prioritize your users, instead of advertisers.",
|
||||
},
|
||||
{
|
||||
Icon: SkynetPersistenceSmall,
|
||||
title: "Persistence",
|
||||
text:
|
||||
"Your skapp and data stay live, even if corporations pull your access to their resources. You can also use Skynet as a failover site for when centralized providers go down.",
|
||||
text: "Your skapp and data stay live, even if corporations pull your access to their resources. You can also use Skynet as a failover site for when centralized providers go down.",
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import curator
|
||||
import elasticsearch
|
||||
import os
|
||||
import ssl
|
||||
import sys
|
||||
|
||||
TIMEOUT=120
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print('USAGE: [INDEX_PREFIX=(default "")] [ARCHIVE=(default false)] ... {} NUM_OF_DAYS http://HOSTNAME[:PORT]'.format(sys.argv[0]))
|
||||
print('NUM_OF_DAYS ... delete indices that are older than the given number of days.')
|
||||
print('HOSTNAME ... specifies which Elasticsearch hosts URL to search and delete indices from.')
|
||||
print('TIMEOUT ... number of seconds to wait for master node response.'.format(TIMEOUT))
|
||||
print('INDEX_PREFIX ... specifies index prefix.')
|
||||
print('INDEX_DATE_SEPARATOR ... specifies index date separator.')
|
||||
print('ARCHIVE ... specifies whether to remove archive indices (only works for rollover) (default false).')
|
||||
print('ROLLOVER ... specifies whether to remove indices created by rollover (default false).')
|
||||
print('ES_USERNAME ... The username required by Elasticsearch.')
|
||||
print('ES_PASSWORD ... The password required by Elasticsearch.')
|
||||
print('ES_TLS ... enable TLS (default false).')
|
||||
print('ES_TLS_CA ... Path to TLS CA file.')
|
||||
print('ES_TLS_CERT ... Path to TLS certificate file.')
|
||||
print('ES_TLS_KEY ... Path to TLS key file.')
|
||||
print('ES_TLS_SKIP_HOST_VERIFY ... (insecure) Skip server\'s certificate chain and host name verification.')
|
||||
sys.exit(1)
|
||||
|
||||
client = create_client(os.getenv("ES_USERNAME"), os.getenv("ES_PASSWORD"), str2bool(os.getenv("ES_TLS", 'false')), os.getenv("ES_TLS_CA"), os.getenv("ES_TLS_CERT"), os.getenv("ES_TLS_KEY"), str2bool(os.getenv("ES_TLS_SKIP_HOST_VERIFY", 'false')))
|
||||
ilo = curator.IndexList(client)
|
||||
empty_list(ilo, 'Elasticsearch has no indices')
|
||||
|
||||
prefix = os.getenv("INDEX_PREFIX", '')
|
||||
if prefix != '':
|
||||
prefix += '-'
|
||||
separator = os.getenv("INDEX_DATE_SEPARATOR", '-')
|
||||
|
||||
if str2bool(os.getenv("ARCHIVE", 'false')):
|
||||
filter_archive_indices_rollover(ilo, prefix)
|
||||
else:
|
||||
if str2bool(os.getenv("ROLLOVER", 'false')):
|
||||
filter_main_indices_rollover(ilo, prefix)
|
||||
else:
|
||||
filter_main_indices(ilo, prefix, separator)
|
||||
|
||||
empty_list(ilo, 'No indices to delete')
|
||||
|
||||
for index in ilo.working_list():
|
||||
print("Removing", index)
|
||||
timeout = int(os.getenv("TIMEOUT", TIMEOUT))
|
||||
delete_indices = curator.DeleteIndices(ilo, master_timeout=timeout)
|
||||
delete_indices.do_action()
|
||||
|
||||
|
||||
def filter_main_indices(ilo, prefix, separator):
|
||||
date_regex = "\d{4}" + separator + "\d{2}" + separator + "\d{2}"
|
||||
time_string = "%Y" + separator + "%m" + separator + "%d"
|
||||
|
||||
ilo.filter_by_regex(kind='regex', value=prefix + "jaeger-(span|service|dependencies)-" + date_regex)
|
||||
empty_list(ilo, "No indices to delete")
|
||||
# This excludes archive index as we use source='name'
|
||||
# source `creation_date` would include archive index
|
||||
ilo.filter_by_age(source='name', direction='older', timestring=time_string, unit='days', unit_count=int(sys.argv[1]))
|
||||
|
||||
|
||||
def filter_main_indices_rollover(ilo, prefix):
|
||||
ilo.filter_by_regex(kind='regex', value=prefix + "jaeger-(span|service)-\d{6}")
|
||||
empty_list(ilo, "No indices to delete")
|
||||
# do not remove active write indices
|
||||
ilo.filter_by_alias(aliases=[prefix + 'jaeger-span-write'], exclude=True)
|
||||
empty_list(ilo, "No indices to delete")
|
||||
ilo.filter_by_alias(aliases=[prefix + 'jaeger-service-write'], exclude=True)
|
||||
empty_list(ilo, "No indices to delete")
|
||||
ilo.filter_by_age(source='creation_date', direction='older', unit='days', unit_count=int(sys.argv[1]))
|
||||
|
||||
|
||||
def filter_archive_indices_rollover(ilo, prefix):
|
||||
# Remove only rollover archive indices
|
||||
# Do not remove active write archive index
|
||||
ilo.filter_by_regex(kind='regex', value=prefix + "jaeger-span-archive-\d{6}")
|
||||
empty_list(ilo, "No indices to delete")
|
||||
ilo.filter_by_alias(aliases=[prefix + 'jaeger-span-archive-write'], exclude=True)
|
||||
empty_list(ilo, "No indices to delete")
|
||||
ilo.filter_by_age(source='creation_date', direction='older', unit='days', unit_count=int(sys.argv[1]))
|
||||
|
||||
|
||||
def empty_list(ilo, error_msg):
|
||||
try:
|
||||
ilo.empty_list_check()
|
||||
except curator.NoIndices:
|
||||
print(error_msg)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def str2bool(v):
|
||||
return v.lower() in ('true', '1')
|
||||
|
||||
|
||||
def create_client(username, password, tls, ca, cert, key, skipHostVerify):
|
||||
context = ssl.create_default_context()
|
||||
if ca is not None:
|
||||
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=ca)
|
||||
elif skipHostVerify:
|
||||
context.check_hostname = False
|
||||
context.verify_mode = ssl.CERT_NONE
|
||||
if username is not None and password is not None:
|
||||
return elasticsearch.Elasticsearch(sys.argv[2:], http_auth=(username, password), ssl_context=context)
|
||||
elif tls:
|
||||
context.load_cert_chain(certfile=cert, keyfile=key)
|
||||
return elasticsearch.Elasticsearch(sys.argv[2:], ssl_context=context)
|
||||
else:
|
||||
return elasticsearch.Elasticsearch(sys.argv[2:], ssl_context=context)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,23 @@
|
|||
#!/bin/sh
|
||||
|
||||
echo $WAIT_COMMAND
|
||||
echo $WAIT_START_CMD
|
||||
|
||||
is_ready() {
|
||||
eval "$WAIT_COMMAND"
|
||||
}
|
||||
|
||||
# wait until is ready
|
||||
i=0
|
||||
while ! is_ready; do
|
||||
i=`expr $i + 1`
|
||||
if [ $i -ge $WAIT_LOOPS ]; then
|
||||
echo "$(date) - still not ready, giving up"
|
||||
exit 1
|
||||
fi
|
||||
echo "$(date) - waiting to be ready"
|
||||
sleep $WAIT_SLEEP
|
||||
done
|
||||
|
||||
#start the script
|
||||
exec $WAIT_START_CMD
|
|
@ -5,7 +5,7 @@ set -e # exit on first error
|
|||
sudo apt-get update
|
||||
sudo apt-get -y install python3-pip
|
||||
|
||||
pip3 install discord.py python-dotenv requests
|
||||
pip3 install discord.py python-dotenv requests elasticsearch-curator
|
||||
|
||||
# add cron entries to user crontab
|
||||
crontab -u user /home/user/skynet-webportal/setup-scripts/support/crontab
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCpBsw5mPBVIvVd5GX43VXWHWuLeR2h0lfw8vRyDFgmV0TqC9r0POfmWOdSo/QlxHOeI+7S8Ahj/JdDarrx3vJ2vJQkK/tN2bPS30tR0pbCkr0vE/lUWsEuVxOXK132wtFQ/pF3CoVipI8THUS7/Dtap/9fujcEm59dIi3obYGc9F+UetmNtrc+mb6KJ6a1hkaXjD12qP03srSQSDBjch/7nbFFzrRwCZ9DJntMu6Ux6NZ7RcFuXPCg0dK0lggEX/Agzh3KHe69dgiMh8sG0WwCb9vWqd6dtapCt7XKZSnEvyFE1YVZgpsd7bCnGe4vPS3kLsvxeojruDo8Oj3b0exHL9+3Rr4ndVVNHkDxhvlQFbGrd5eiG/brvGjS+ibscTuNukLeiCmBrI5KULObynI2dEQVQKREVywU/qX+xm68noEGBbiRt2L2ImyJvgpNdlyCkDyFhBTo/HtH1WHP1WJijfCHM3jxigeLPRV0GChKK1RbYjZIi6JNsalW7yad/qzHDzht+jBHHAjD4qGlfuNtzP4hs3FErGiQMVZ8g9Tgq8SxPLNOULpcCSwsLLlzfrLYdv52IgkwTIAFR9W+xHGrWypCba9pfskXWXlRNM61qYf3//H0BGHxtuNAASkJrVWwcCuOVN6/EcJOTS9qkg3JiWqs79z0F2I14+AfPFgBKQ== david@nebulouslabs.com
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCr3nrSQ+ag5gEm9LBoiw68UKALboot+Eemv0TbP6BPnvB6bnSdDstb7Eu1Dkla8uiyw3w2ZYi5Pg4dS5W8vnxwXvey8gBd3GYLpjtnSp9ukeYjHK0J2aX4PBC4GXvRSRjKxYfHauUqm8PaA4uQ4sBkblfwWDEH94um1yyqIamTabH6mfsYiaiiwTNu7ldZOAIlKR/G7cXlLmFz46An7Mn2wwbuv2Khin/f2bLtUF/smOolI7pjOH6ifhHR9LxotcY/xL+E5jRbU1XxldFvVXkL5CU8tEinE6oigwMH9zsPZr+Z70Q/wm20cylxNJu8qdMGQW+WhDg3S70KpCmjYlWJ6bF1HL3z9UkN0lS1EM21n13RIx1iEO7SEC3YPl8VqZiZS7P9Uf5D5z/vTG+fWouCsCBMSbq3HUcNXlm5MLGSdBWPKzZsUaCkHkQks/sxHVy21YAM/3xgST1a05PbIJU1RsqJ0wh0J2gg7/fBUE0ljFyKZ36mvfg6BNlwCUydAiVaQt1geqh+8/VRwjTw/jtHb8G7QhSNwDNo1BcQPU3LkdKePqgldyP5EYGl9bI4E4sYc2DooeJ22fXpWfuClLB+JcHGuCJf/Hg6si9IeeXKm8PwaBdxIVytRPEeJR+q5uOwzI4XWNgERdGU/UVbgfnrAPMuVPa9Jhyl96U9uUl+Cw== peterjan.brone@gmail.com
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDMmZFdJsqig/zX7Ly7qJMMDomsdAKLgl7W7ET1w7xH9BBM48OCWmozuLCfCG8MUCEYSUD575hA028hNi6CAK40J3fF74IDDyc9DUb+le8Y8EuzHPKxYLE/gWsjr70XOcZcC4IxLcADQgpeLjrPZQs7A4EYfdxnTTLJVYrowZ9RR5ivcKBjyFOiQyCuFSIvtYMo11Xm2gU48SKYGJThhHUiE2kMOlH3notXJ+T81927IGJdza7J3DAyKtMGB2HEMA89ma3mvEvbPTDMggJFJ3VG7sukRLq6UmT7BT+f3BW+Nr87A1o4upkAuXdkL9cUrris7kQN61AcaCNFU/CuIJa4dUZ0nt+z5X7kWtc0zD75EPj3w6AjB+E1+MSPsqnxd5PnGtSCQqHoa5hg4hQMSweC2tQhSKoWDfx9W2fZiLpg1IL6QB5xCxjg+YKCXEJKxRwXDtbh1DHFdJ5N1kM7IDSeeblc80HNxYrJUPNH1ExWsPl11gmBEEWDAiRSet4bAnOmgDYcJ9Aw2KAndb01cNsw5RL0Dg/W63tb8S5Y9kz6spX6X91yz53JzrozZO7VFfKxa17nubPEeWPTqAQ3uRWPvpdbivVnOAoFCLacRvtTfvetuz/vGZ3JTpr6Ylb9Z76cIqpFe70+bnauZwmxjF+EEq2+u3gd2uewuV2//o+CYQ== kwypchlo@gmail.com
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDgiq1etF0aD94rG/UVmYEt4ij5K8MvHZwb4wIUi6Ihr david@nebulouslabs.com
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAyIT2HqzDhQs6jS89ZsnY6+GJEklVMqF6fXe/i5s8d7 chris@nebulous.tech
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFxLuZzjmFN9CgVOI5vaiVhQgMwG9dLQJ688wrsbpHH/ ivaylo@nebulous.tech
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINbAhwjJNAud7YIJvLth2bmeUg3kO20xl7ZfqBTvoXn8 Filip Rysavy
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG67M3zC4eDJEjma0iKKksGclteKbB86ONQtBaWY93M6 mjsevey@gmail.com
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN6Kcx8yetova4/ALUQHigo/PBMJO33ZTKOsg2jxSO2a user@depl.siasky.dev
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDgiq1etF0aD94rG/UVmYEt4ij5K8MvHZwb4wIUi6Ihr david@siasky.net
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAyIT2HqzDhQs6jS89ZsnY6+GJEklVMqF6fXe/i5s8d7 chris@siasky.net
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFxLuZzjmFN9CgVOI5vaiVhQgMwG9dLQJ688wrsbpHH/ ivaylo@siasky.net
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINbAhwjJNAud7YIJvLth2bmeUg3kO20xl7ZfqBTvoXn8 filip@siasky.net
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG67M3zC4eDJEjma0iKKksGclteKbB86ONQtBaWY93M6 matt@siasky.net
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF+XC8f0dumhzDE93i9IIMsMp7/MJPwGH+Uc9JFKOvyw karol@siasky.net
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPM43lzbKjFLChe5rKETxDpWpNlqXCGTBPiWlDN2vlLD pj@siasky.net
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN6Kcx8yetova4/ALUQHigo/PBMJO33ZTKOsg2jxSO2a user@deploy.siasky.dev
|
||||
|
|
Reference in New Issue