*Prune out old or unneeded code, some maybe be refactored back in as plugins or in a different form
ci/woodpecker/push/woodpecker Pipeline failed
Details
ci/woodpecker/push/woodpecker Pipeline failed
Details
This commit is contained in:
parent
6fa5ccd49a
commit
457398b291
|
@ -31,7 +31,6 @@ config.inject({
|
|||
logLevel: "info",
|
||||
pluginDir: path.resolve(configDir, "..", "plugins"),
|
||||
plugins: ["core"],
|
||||
ssl: false,
|
||||
});
|
||||
|
||||
config.load({
|
||||
|
|
|
@ -4,7 +4,6 @@ import { start as startApp } from "./modules/app";
|
|||
import log from "loglevel";
|
||||
import config from "./config.js";
|
||||
import { loadPlugins } from "./modules/plugin.js";
|
||||
import { start as startSSl } from "./modules/ssl.js";
|
||||
import { start as startSwarm } from "./modules/swarm.js";
|
||||
import * as bip39 from "@scure/bip39";
|
||||
import { wordlist } from "@scure/bip39/wordlists/english";
|
||||
|
@ -22,7 +21,6 @@ async function boot() {
|
|||
await loadPlugins();
|
||||
await startApp();
|
||||
await startRpc();
|
||||
await startSSl();
|
||||
await startRelay();
|
||||
}
|
||||
|
||||
|
|
445
src/lib/file.ts
445
src/lib/file.ts
|
@ -1,445 +0,0 @@
|
|||
import type { Err, progressiveFetchResult } from "libskynet";
|
||||
// @ts-ignore
|
||||
import { SkynetClient } from "@skynetlabs/skynet-nodejs";
|
||||
import type {
|
||||
IndependentFileSmall,
|
||||
IndependentFileSmallMetadata,
|
||||
} from "@lumeweb/relay-types";
|
||||
import {
|
||||
addContextToErr,
|
||||
blake2b,
|
||||
bufToHex,
|
||||
ed25519Sign,
|
||||
encodePrefixedBytes,
|
||||
encodeU64,
|
||||
defaultPortalList,
|
||||
skylinkToResolverEntryData,
|
||||
encryptFileSmall,
|
||||
decryptFileSmall,
|
||||
entryIDToSkylink,
|
||||
deriveRegistryEntryID,
|
||||
taggedRegistryEntryKeys,
|
||||
namespaceInode,
|
||||
deriveChildSeed,
|
||||
bufToB64,
|
||||
} from "libskynet";
|
||||
|
||||
import { readRegistryEntry, progressiveFetch, upload } from "libskynetnode";
|
||||
|
||||
const ERR_NOT_EXISTS = "DNE";
|
||||
const STD_FILENAME = "file";
|
||||
|
||||
async function overwriteRegistryEntry(
|
||||
keypair: any,
|
||||
datakey: Uint8Array,
|
||||
data: Uint8Array,
|
||||
revision: bigint
|
||||
): Promise<null> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (data.length > 86) {
|
||||
reject("provided data is too large to fit in a registry entry");
|
||||
return;
|
||||
}
|
||||
|
||||
let [encodedRevision, errU64] = encodeU64(revision);
|
||||
if (errU64 !== null) {
|
||||
reject(addContextToErr(errU64, "unable to encode revision number"));
|
||||
return;
|
||||
}
|
||||
|
||||
let datakeyHex = bufToHex(datakey);
|
||||
let [encodedData, errEPB] = encodePrefixedBytes(data);
|
||||
if (errEPB !== null) {
|
||||
reject(addContextToErr(errEPB, "unable to encode the registry data"));
|
||||
return;
|
||||
}
|
||||
let dataToSign = new Uint8Array(32 + 8 + data.length + 8);
|
||||
dataToSign.set(datakey, 0);
|
||||
dataToSign.set(encodedData, 32);
|
||||
dataToSign.set(encodedRevision, 32 + 8 + data.length);
|
||||
let sigHash = blake2b(dataToSign);
|
||||
let [sig, errS] = ed25519Sign(sigHash, keypair.secretKey);
|
||||
if (errS !== null) {
|
||||
reject(addContextToErr(errS, "unable to produce signature"));
|
||||
return;
|
||||
}
|
||||
|
||||
let postBody = {
|
||||
publickey: {
|
||||
algorithm: "ed25519",
|
||||
key: Array.from(keypair.publicKey),
|
||||
},
|
||||
datakey: datakeyHex,
|
||||
revision: Number(revision),
|
||||
data: Array.from(data),
|
||||
signature: Array.from(sig),
|
||||
};
|
||||
let fetchOpts = {
|
||||
method: "post",
|
||||
body: JSON.stringify(postBody),
|
||||
};
|
||||
let endpoint = "/skynet/registry";
|
||||
|
||||
progressiveFetch(
|
||||
endpoint,
|
||||
fetchOpts,
|
||||
defaultPortalList,
|
||||
verifyRegistryWrite
|
||||
).then((result: progressiveFetchResult) => {
|
||||
if (result.success === true) {
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
reject("unable to write registry entry\n" + JSON.stringify(result));
|
||||
});
|
||||
});
|
||||
}
|
||||
async function verifyRegistryWrite(response: Response): Promise<Err> {
|
||||
return new Promise((resolve) => {
|
||||
if (!("status" in response)) {
|
||||
resolve("response did not contain a status");
|
||||
return;
|
||||
}
|
||||
if (response.status === 204) {
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
resolve("unrecognized status");
|
||||
});
|
||||
}
|
||||
|
||||
async function createIndependentFileSmall(
|
||||
seed: Uint8Array,
|
||||
userInode: string,
|
||||
fileData: Uint8Array
|
||||
): Promise<[IndependentFileSmall, Err]> {
|
||||
return new Promise(async (resolve) => {
|
||||
let [inode, errNI] = namespaceInode("IndependentFileSmall", userInode);
|
||||
if (errNI !== null) {
|
||||
resolve([{} as any, addContextToErr(errNI, "unable to namespace inode")]);
|
||||
return;
|
||||
}
|
||||
|
||||
let [keypair, dataKey, errTREK] = taggedRegistryEntryKeys(
|
||||
seed,
|
||||
inode,
|
||||
inode
|
||||
);
|
||||
if (errTREK !== null) {
|
||||
resolve([
|
||||
{} as any,
|
||||
addContextToErr(
|
||||
errTREK,
|
||||
"unable to get registry entry for provided inode"
|
||||
),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = await readRegistryEntry(keypair.publicKey, dataKey);
|
||||
} catch (e) {
|
||||
result = { exists: false };
|
||||
}
|
||||
if (result.exists === true) {
|
||||
resolve([{} as any, "exists"]);
|
||||
return;
|
||||
}
|
||||
|
||||
let encryptionKey = deriveChildSeed(seed, inode);
|
||||
let metadata: IndependentFileSmallMetadata = {
|
||||
largestHistoricSize: BigInt(fileData.length),
|
||||
};
|
||||
|
||||
let revisionSeed = new Uint8Array(seed.length + 8);
|
||||
revisionSeed.set(seed, 0);
|
||||
let revisionKey = deriveChildSeed(revisionSeed, inode);
|
||||
let revision = BigInt(revisionKey[0]) * 256n + BigInt(revisionKey[1]);
|
||||
let [encryptedData, errEF] = encryptFileSmall(
|
||||
encryptionKey,
|
||||
inode,
|
||||
revision,
|
||||
metadata,
|
||||
fileData,
|
||||
metadata.largestHistoricSize
|
||||
);
|
||||
if (errEF !== null) {
|
||||
resolve([{} as any, addContextToErr(errEF, "unable to encrypt file")]);
|
||||
return;
|
||||
}
|
||||
|
||||
let immutableSkylink;
|
||||
|
||||
try {
|
||||
immutableSkylink = await upload(encryptedData, {
|
||||
Filename: STD_FILENAME,
|
||||
});
|
||||
} catch (e) {
|
||||
resolve([{} as any, addContextToErr(e, "upload failed")]);
|
||||
return;
|
||||
}
|
||||
|
||||
let [entryData, errSTRED] = skylinkToResolverEntryData(immutableSkylink);
|
||||
if (errSTRED !== null) {
|
||||
resolve([
|
||||
{} as any,
|
||||
addContextToErr(
|
||||
errSTRED,
|
||||
"couldn't create resovler link from upload skylink"
|
||||
),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await overwriteRegistryEntry(keypair, dataKey, entryData, revision);
|
||||
} catch (e: any) {
|
||||
resolve([
|
||||
{} as any,
|
||||
addContextToErr(e, "could not write to registry entry"),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
let [entryID, errDREID] = deriveRegistryEntryID(keypair.publicKey, dataKey);
|
||||
if (errDREID !== null) {
|
||||
resolve([
|
||||
{} as any,
|
||||
addContextToErr(errDREID, "could not compute entry id"),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
let skylink = entryIDToSkylink(entryID);
|
||||
|
||||
let encStr = bufToB64(encryptionKey);
|
||||
let viewKey = encStr + inode;
|
||||
|
||||
let ifile: IndependentFileSmall = {
|
||||
dataKey,
|
||||
fileData,
|
||||
inode,
|
||||
keypair,
|
||||
metadata,
|
||||
revision,
|
||||
seed,
|
||||
|
||||
skylink,
|
||||
viewKey,
|
||||
|
||||
overwriteData: function (newData: Uint8Array): Promise<Err> {
|
||||
return overwriteIndependentFileSmall(ifile, newData);
|
||||
},
|
||||
readData: function (): Promise<[Uint8Array, Err]> {
|
||||
return new Promise((resolve) => {
|
||||
let data = new Uint8Array(ifile.fileData.length);
|
||||
data.set(ifile.fileData, 0);
|
||||
resolve([data, null]);
|
||||
});
|
||||
},
|
||||
};
|
||||
resolve([ifile, null]);
|
||||
});
|
||||
}
|
||||
|
||||
async function openIndependentFileSmall(
|
||||
seed: Uint8Array,
|
||||
userInode: string
|
||||
): Promise<[IndependentFileSmall, Err]> {
|
||||
return new Promise(async (resolve) => {
|
||||
let [inode, errNI] = namespaceInode("IndependentFileSmall", userInode);
|
||||
if (errNI !== null) {
|
||||
resolve([{} as any, addContextToErr(errNI, "unable to namespace inode")]);
|
||||
return;
|
||||
}
|
||||
|
||||
let [keypair, dataKey, errTREK] = taggedRegistryEntryKeys(
|
||||
seed,
|
||||
inode,
|
||||
inode
|
||||
);
|
||||
if (errTREK !== null) {
|
||||
resolve([
|
||||
{} as any,
|
||||
addContextToErr(
|
||||
errTREK,
|
||||
"unable to get registry entry for provided inode"
|
||||
),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = await readRegistryEntry(keypair.publicKey, dataKey);
|
||||
} catch (e: any) {
|
||||
resolve([
|
||||
{} as any,
|
||||
addContextToErr(e, "unable to read registry entry for file"),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
if (result.exists !== true) {
|
||||
resolve([{} as any, ERR_NOT_EXISTS]);
|
||||
return;
|
||||
}
|
||||
|
||||
let [entryID, errDREID] = deriveRegistryEntryID(keypair.publicKey, dataKey);
|
||||
if (errDREID !== null) {
|
||||
resolve([
|
||||
{} as any,
|
||||
addContextToErr(errDREID, "unable to derive registry entry id"),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
let skylink = entryIDToSkylink(entryID);
|
||||
|
||||
const client = new SkynetClient("https://web3portal.com");
|
||||
let encryptedData;
|
||||
try {
|
||||
encryptedData = await client.downloadData(skylink);
|
||||
} catch (e: any) {
|
||||
resolve([{} as any, addContextToErr(e, "unable to download file")]);
|
||||
return;
|
||||
}
|
||||
|
||||
let encryptionKey = deriveChildSeed(seed, inode);
|
||||
let [metadata, fileData, errDF] = decryptFileSmall(
|
||||
encryptionKey,
|
||||
inode,
|
||||
encryptedData
|
||||
);
|
||||
if (errDF !== null) {
|
||||
resolve([{} as any, addContextToErr(errDF, "unable to decrypt file")]);
|
||||
return;
|
||||
}
|
||||
|
||||
let encStr = bufToB64(encryptionKey);
|
||||
let viewKey = encStr + inode;
|
||||
|
||||
let ifile: IndependentFileSmall = {
|
||||
dataKey,
|
||||
fileData,
|
||||
inode,
|
||||
keypair,
|
||||
metadata,
|
||||
revision: result.revision!,
|
||||
seed,
|
||||
|
||||
skylink,
|
||||
viewKey,
|
||||
|
||||
overwriteData: function (newData: Uint8Array): Promise<Err> {
|
||||
return overwriteIndependentFileSmall(ifile, newData);
|
||||
},
|
||||
|
||||
readData: function (): Promise<[Uint8Array, Err]> {
|
||||
return new Promise((resolve) => {
|
||||
let data = new Uint8Array(ifile.fileData.length);
|
||||
data.set(ifile.fileData, 0);
|
||||
resolve([data, null]);
|
||||
});
|
||||
},
|
||||
};
|
||||
resolve([ifile, null]);
|
||||
});
|
||||
}
|
||||
async function overwriteIndependentFileSmall(
|
||||
file: IndependentFileSmall,
|
||||
newData: Uint8Array
|
||||
): Promise<Err> {
|
||||
return new Promise(async (resolve) => {
|
||||
// Create a new metadata for the file based on the current file
|
||||
// metadata. Need to update the largest historic size.
|
||||
let newMetadata: IndependentFileSmallMetadata = {
|
||||
largestHistoricSize: BigInt(file.metadata.largestHistoricSize),
|
||||
};
|
||||
if (BigInt(newData.length) > newMetadata.largestHistoricSize) {
|
||||
newMetadata.largestHistoricSize = BigInt(newData.length);
|
||||
}
|
||||
|
||||
// Compute the new revision number for the file. This is done
|
||||
// deterministically using the seed and the current revision number, so
|
||||
// that multiple concurrent updates will end up with the same revision.
|
||||
// We use a random number between 1 and 256 for our increment.
|
||||
let [encodedRevision, errEU64] = encodeU64(file.revision);
|
||||
if (errEU64 !== null) {
|
||||
resolve(addContextToErr(errEU64, "unable to encode revision"));
|
||||
return;
|
||||
}
|
||||
let revisionSeed = new Uint8Array(
|
||||
file.seed.length + encodedRevision.length
|
||||
);
|
||||
revisionSeed.set(file.seed, 0);
|
||||
revisionSeed.set(encodedRevision, file.seed.length);
|
||||
let revisionKey = deriveChildSeed(revisionSeed, file.inode);
|
||||
let newRevision = file.revision + BigInt(revisionKey[0]) + 1n;
|
||||
|
||||
// Get the encryption key.
|
||||
let encryptionKey = deriveChildSeed(file.seed, file.inode);
|
||||
|
||||
// Create a new encrypted blob for the data.
|
||||
//
|
||||
// NOTE: Need to supply the data that would be in place after a
|
||||
// successful update, which means using the new metadata and revision
|
||||
// number.
|
||||
let [encryptedData, errEFS] = encryptFileSmall(
|
||||
encryptionKey,
|
||||
file.inode,
|
||||
newRevision,
|
||||
newMetadata,
|
||||
newData,
|
||||
newMetadata.largestHistoricSize
|
||||
);
|
||||
if (errEFS !== null) {
|
||||
resolve(addContextToErr(errEFS, "unable to encrypt updated file"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Upload the data to get the immutable link.
|
||||
let skylink;
|
||||
try {
|
||||
skylink = await upload(encryptedData, {
|
||||
Filename: STD_FILENAME,
|
||||
});
|
||||
} catch (e) {
|
||||
resolve(addContextToErr(e, "new data upload failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Write to the registry entry.
|
||||
let [entryData, errSTRED] = skylinkToResolverEntryData(skylink);
|
||||
if (errSTRED !== null) {
|
||||
resolve(
|
||||
addContextToErr(
|
||||
errSTRED,
|
||||
"could not create resolver link from upload skylink"
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await overwriteRegistryEntry(
|
||||
file.keypair,
|
||||
file.dataKey,
|
||||
entryData,
|
||||
newRevision
|
||||
);
|
||||
} catch (e: any) {
|
||||
resolve(addContextToErr(e, "could not write to registry entry"));
|
||||
return;
|
||||
}
|
||||
|
||||
// File update was successful, update the file metadata.
|
||||
file.revision = newRevision;
|
||||
file.metadata = newMetadata;
|
||||
file.fileData = newData;
|
||||
resolve(null);
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
createIndependentFileSmall,
|
||||
openIndependentFileSmall,
|
||||
overwriteIndependentFileSmall,
|
||||
};
|
|
@ -1,151 +0,0 @@
|
|||
import tls from "tls";
|
||||
import {
|
||||
createIndependentFileSmall,
|
||||
openIndependentFileSmall,
|
||||
overwriteIndependentFileSmall,
|
||||
} from "../lib/file.js";
|
||||
// @ts-ignore
|
||||
import promiseRetry from "promise-retry";
|
||||
import config from "../config.js";
|
||||
import log from "loglevel";
|
||||
import { getSeed } from "../lib/seed.js";
|
||||
import type {
|
||||
IndependentFileSmall,
|
||||
SavedSslData,
|
||||
SslData,
|
||||
} from "@lumeweb/relay-types";
|
||||
|
||||
let sslCtx: tls.SecureContext = tls.createSecureContext();
|
||||
let sslObject: SslData = {};
|
||||
let sslChecker: () => Promise<void>;
|
||||
|
||||
const FILE_CERT_NAME = "/lumeweb/relay/ssl.crt";
|
||||
const FILE_KEY_NAME = "/lumeweb/relay/ssl.key";
|
||||
|
||||
export function setSslContext(context: tls.SecureContext) {
|
||||
sslCtx = context;
|
||||
}
|
||||
|
||||
export function getSslContext(): tls.SecureContext {
|
||||
return sslCtx;
|
||||
}
|
||||
|
||||
export function setSsl(
|
||||
cert: IndependentFileSmall | Uint8Array,
|
||||
key: IndependentFileSmall | Uint8Array
|
||||
): void {
|
||||
cert = (cert as IndependentFileSmall)?.fileData || cert;
|
||||
key = (key as IndependentFileSmall)?.fileData || key;
|
||||
sslObject.cert = cert as Uint8Array;
|
||||
sslObject.key = key as Uint8Array;
|
||||
setSslContext(
|
||||
tls.createSecureContext({
|
||||
cert: Buffer.from(cert),
|
||||
key: Buffer.from(key),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function getSsl(): SslData {
|
||||
return sslObject;
|
||||
}
|
||||
|
||||
export async function saveSSl(): Promise<void> {
|
||||
const seed = getSeed();
|
||||
|
||||
log.info(`Saving SSL Certificate for ${config.str("domain")}`);
|
||||
|
||||
let oldCert = await getSslCert();
|
||||
let cert: any = getSsl()?.cert;
|
||||
if (oldCert) {
|
||||
await overwriteIndependentFileSmall(
|
||||
oldCert as IndependentFileSmall,
|
||||
Buffer.from(cert)
|
||||
);
|
||||
} else {
|
||||
await createIndependentFileSmall(seed, FILE_CERT_NAME, Buffer.from(cert));
|
||||
}
|
||||
|
||||
let oldKey = await getSslKey();
|
||||
let key: any = getSsl()?.key;
|
||||
|
||||
if (oldKey) {
|
||||
await overwriteIndependentFileSmall(
|
||||
oldKey as IndependentFileSmall,
|
||||
Buffer.from(key)
|
||||
);
|
||||
} else {
|
||||
await createIndependentFileSmall(seed, FILE_KEY_NAME, Buffer.from(key));
|
||||
}
|
||||
|
||||
log.info(`Saved SSL Certificate for ${config.str("domain")}`);
|
||||
}
|
||||
|
||||
export async function getSavedSsl(
|
||||
retry = true
|
||||
): Promise<boolean | SavedSslData> {
|
||||
let retryOptions = retry ? {} : { retries: 0 };
|
||||
let sslCert: IndependentFileSmall | boolean = false;
|
||||
let sslKey: IndependentFileSmall | boolean = false;
|
||||
|
||||
try {
|
||||
await promiseRetry(async (retry: any) => {
|
||||
sslCert = await getSslCert();
|
||||
if (!sslCert) {
|
||||
retry();
|
||||
}
|
||||
}, retryOptions);
|
||||
|
||||
await promiseRetry(async (retry: any) => {
|
||||
sslKey = await getSslKey();
|
||||
if (!sslKey) {
|
||||
retry();
|
||||
}
|
||||
}, retryOptions);
|
||||
} catch {}
|
||||
|
||||
if (!sslCert || !sslKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return {
|
||||
cert: sslCert as IndependentFileSmall,
|
||||
key: sslKey as IndependentFileSmall,
|
||||
};
|
||||
}
|
||||
|
||||
async function getSslCert(): Promise<IndependentFileSmall | boolean> {
|
||||
return getSslFile(FILE_CERT_NAME);
|
||||
}
|
||||
|
||||
async function getSslKey(): Promise<IndependentFileSmall | boolean> {
|
||||
return getSslFile(FILE_KEY_NAME);
|
||||
}
|
||||
|
||||
async function getSslFile(
|
||||
name: string
|
||||
): Promise<IndependentFileSmall | boolean> {
|
||||
let seed = getSeed();
|
||||
|
||||
let [file, err] = await openIndependentFileSmall(seed, name);
|
||||
|
||||
if (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
export function setSSlCheck(checker: () => Promise<void>): void {
|
||||
sslChecker = checker;
|
||||
}
|
||||
|
||||
export function getSslCheck(): () => Promise<void> {
|
||||
return sslChecker;
|
||||
}
|
||||
|
||||
export async function start() {
|
||||
if (config.bool("ssl") && getSslCheck()) {
|
||||
await getSslCheck()();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue