Skip to content
Closed

P2P #44

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "drop-base"]
path = drop-base
url = https://github.com/Drop-OSS/drop-base.git
url = https://github.com/Drop-OSS/drop-base.git
26 changes: 15 additions & 11 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ import tailwindcss from "@tailwindcss/vite";

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
extends: ["./drop-base"],

// Module config from here down
modules: [
"vue3-carousel-nuxt",
"nuxt-security",
// "@nuxt/image",
"@nuxt/fonts",
"@nuxt/eslint",
],

// Nuxt-only config
telemetry: false,
compatibilityDate: "2024-04-03",
Expand All @@ -21,6 +32,10 @@ export default defineNuxtConfig({
viewTransition: true,
},

// future: {
// compatibilityVersion: 4,
// },

vite: {
plugins: [tailwindcss()],
},
Expand Down Expand Up @@ -76,17 +91,6 @@ export default defineNuxtConfig({
},
},

extends: ["./drop-base"],

// Module config from here down
modules: [
"vue3-carousel-nuxt",
"nuxt-security",
// "@nuxt/image",
"@nuxt/fonts",
"@nuxt/eslint",
],

carousel: {
prefix: "Vue",
},
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
},
"dependencies": {
"@drop-oss/droplet": "^0.7.2",
"@drop-oss/headscalez": "0.0.4",
"@headlessui/vue": "^1.7.23",
"@heroicons/vue": "^2.1.5",
"@nuxt/fonts": "^0.11.0",
Expand Down Expand Up @@ -56,7 +57,8 @@
"@types/turndown": "^5.0.5",
"autoprefixer": "^10.4.20",
"eslint": "^9.24.0",
"eslint-config-prettier": "^10.1.1",
"eslint-config-prettier": "^10.1.5",
"eslint-plugin-prettier": "^5.4.0",
"h3": "^1.15.1",
"ofetch": "^1.4.1",
"postcss": "^8.4.47",
Expand Down
20 changes: 20 additions & 0 deletions server/api/v1/client/peer/index.get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ClientCapabilities } from "~/prisma/client";
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import headscaleManager from "~/server/internal/p2p/headscale";

export default defineClientEventHandler(async (h3, { fetchClient }) => {
const client = await fetchClient();
if (!client.capabilities.includes(ClientCapabilities.PeerAPI))
throw createError({
statusCode: 403,
statusMessage: "Capability not allowed.",
});

if (!headscaleManager.enabled())
throw createError({
statusCode: 500,
statusMessage: "Peer network not available.",
});

return headscaleManager.configuration();
});
26 changes: 26 additions & 0 deletions server/api/v1/client/peer/index.post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ClientCapabilities } from "~/prisma/client";
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import headscaleManager from "~/server/internal/p2p/headscale";

export default defineClientEventHandler(
async (h3, { fetchClient, fetchUser }) => {
const client = await fetchClient();
if (!client.capabilities.includes(ClientCapabilities.PeerAPI))
throw createError({
statusCode: 403,
statusMessage: "Capability not allowed.",
});

if (!headscaleManager.enabled())
throw createError({
statusCode: 500,
statusMessage: "Peer network not available.",
});

const user = await fetchUser();

const key = await headscaleManager.createPreauthKey(user, client);

return key;
},
);
4 changes: 3 additions & 1 deletion server/internal/clients/ca-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import path from "path";
import fs from "fs";
import type { CertificateBundle } from "./ca";
import prisma from "../db/database";
import { systemConfig } from "../config/sys-conf";

export type CertificateStore = {
store(name: string, data: CertificateBundle): Promise<void>;
Expand All @@ -10,7 +11,8 @@ export type CertificateStore = {
checkBlacklistCertificate(name: string): Promise<boolean>;
};

export const fsCertificateStore = (base: string) => {
export const fsCertificateStore = () => {
const base = path.join(systemConfig.getDataFolder(), "certs");
const blacklist = path.join(base, ".blacklist");
fs.mkdirSync(blacklist, { recursive: true });
const store: CertificateStore = {
Expand Down
21 changes: 21 additions & 0 deletions server/internal/config/sys-conf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import path from "path";

class SystemConfig {
private libraryFolder = process.env.LIBRARY ?? "./.data/library";
private dataFolder = process.env.DATA ?? "./.data/data";
private headscaleFolder = path.join(this.dataFolder, "headscale");

getLibraryFolder() {
return this.libraryFolder;
}

getDataFolder() {
return this.dataFolder;
}

getHeadscaleFolder() {
return this.headscaleFolder;
}
}

export const systemConfig = new SystemConfig();
3 changes: 2 additions & 1 deletion server/internal/library/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ import taskHandler from "../tasks";
import { parsePlatform } from "../utils/parseplatform";
import droplet from "@drop-oss/droplet";
import notificationSystem from "../notifications";
import { systemConfig } from "../config/sys-conf";

class LibraryManager {
private basePath: string;

constructor() {
this.basePath = process.env.LIBRARY ?? "./.data/library";
this.basePath = systemConfig.getLibraryFolder();
fs.mkdirSync(this.basePath, { recursive: true });
}

Expand Down
3 changes: 2 additions & 1 deletion server/internal/objects/fsBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Readable } from "stream";
import { createHash } from "crypto";
import prisma from "../db/database";
import cacheHandler from "../cache";
import { systemConfig } from "../config/sys-conf";

export class FsObjectBackend extends ObjectBackend {
private baseObjectPath: string;
Expand All @@ -16,7 +17,7 @@ export class FsObjectBackend extends ObjectBackend {

constructor() {
super();
const basePath = process.env.FS_BACKEND_PATH ?? "./.data/objects";
const basePath = path.join(systemConfig.getDataFolder(), "objects");
this.baseObjectPath = path.join(basePath, "objects");
this.baseMetadataPath = path.join(basePath, "metadata");

Expand Down
82 changes: 82 additions & 0 deletions server/internal/p2p/headscale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import type { HeadscaleService } from "@drop-oss/headscalez";
import { HeadscaleControlService, startHeadscale } from "@drop-oss/headscalez";
import { systemConfig } from "../config/sys-conf";
import type { Client, User } from "~/prisma/client";

export class HeadscaleManager {
private controlURL?: string;
private headscaleService?: HeadscaleService;
private headscaleClient?: HeadscaleControlService;

constructor() {
this.setup();
}

async setup() {
const externalUrl = process.env.CONTROL_URL;
if (externalUrl) {
this.controlURL = externalUrl;
const headscale = await startHeadscale({
externalUrl,
dir: systemConfig.getHeadscaleFolder(),
});
this.headscaleService = headscale;
this.headscaleClient = new HeadscaleControlService(headscale);
}
}

enabled() {
return !!this.headscaleService;
}

configuration() {
if (!this.controlURL) throw new Error("Headscale not available");
return {
controlURL: this.controlURL,
};
}

private async fetchUser(user: User) {
if (!this.headscaleClient)
throw new Error("Headscale client not available");
const { response } = await this.headscaleClient.client.listUsers({
id: 0n,
name: user.id,
email: "",
});

if (response.users.length == 0) {
const { response } = await this.headscaleClient.client.createUser({
name: user.id,
displayName: user.displayName,
email: user.email,
pictureUrl: user.profilePictureObjectId,
});

if (!response.user) throw new Error("Could not create user");

return response.user;
}

return response.users[0];
}

async createPreauthKey(user: User, client: Client) {
if (!this.headscaleClient)
throw new Error("Headscale client not available");

const headscaleUser = await this.fetchUser(user);
const { response } = await this.headscaleClient.client.createPreAuthKey({
user: headscaleUser.name,
reusable: false,
ephemeral: false,
aclTags: ["client", `user:${user.id}`, `client:${client.id}`],
});

if (!response.preAuthKey) throw new Error("Could not create pre-auth key");
return response.preAuthKey;
}
}

export const headscaleManager = new HeadscaleManager();
export default headscaleManager;
4 changes: 1 addition & 3 deletions server/plugins/ca.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ export const useCertificateAuthority = () => {
};

export default defineNitroPlugin(async () => {
// const basePath = process.env.CLIENT_CERTIFICATES ?? "./certs";
// fs.mkdirSync(basePath, { recursive: true });
// const store = fsCertificateStore(basePath);
// const store = fsCertificateStore();

ca = await CertificateAuthority.new(dbCertificateStore());
});
Loading