start adding webpush and change index api
This commit is contained in:
parent
647649f9d9
commit
d237044040
@ -30,12 +30,12 @@
|
||||
|
||||
async function loadGlobalEnv() {
|
||||
try {
|
||||
const res = await fetch("/api/v9/policies/instance/domains");
|
||||
const res = await fetch("/.well-known/spacebar/client");
|
||||
const data = await res.json();
|
||||
|
||||
window.GLOBAL_ENV = {
|
||||
API_ENDPOINT: protocolRelative(data.apiEndpoint),
|
||||
WEBAPP_ENDPOINT: protocolRelative(data.apiEndpoint.replace(/\/api$/, '')),
|
||||
API_ENDPOINT: protocolRelative(data.api.baseUrl) + "/api/v9",
|
||||
WEBAPP_ENDPOINT: protocolRelative(data.api.baseUrl),
|
||||
CDN_HOST: protocolRelative(data.cdn),
|
||||
ASSET_ENDPOINT: protocolRelative(data.cdn),
|
||||
MEDIA_PROXY_ENDPOINT: protocolRelative(data.cdn),
|
||||
@ -44,17 +44,17 @@
|
||||
GUILD_TEMPLATE_HOST: 'discord.new',
|
||||
GIFT_CODE_HOST: 'discord.gift',
|
||||
RELEASE_CHANNEL: 'stable',
|
||||
MARKETING_ENDPOINT: protocolRelative(data.apiEndpoint.replace(/\/api$/, '')),
|
||||
MARKETING_ENDPOINT: protocolRelative(data.api.baseUrl),
|
||||
BRAINTREE_KEY: 'production_5st77rrc_49pp2rp4phym7387',
|
||||
STRIPE_KEY: 'pk_live_CUQtlpQUF0vufWpnpUmQvcdi',
|
||||
NETWORKING_ENDPOINT: protocolRelative(data.apiEndpoint.replace(/\/api$/, '')),
|
||||
RTC_LATENCY_ENDPOINT: protocolRelative(data.apiEndpoint.replace(/\/api$/, '')),
|
||||
ACTIVITY_APPLICATION_HOST: protocolRelative(data.apiEndpoint.replace(/\/api$/, '')),
|
||||
NETWORKING_ENDPOINT: protocolRelative(data.api.baseUrl),
|
||||
RTC_LATENCY_ENDPOINT: protocolRelative(data.api.baseUrl),
|
||||
ACTIVITY_APPLICATION_HOST: protocolRelative(data.api.baseUrl),
|
||||
PROJECT_ENV: 'production',
|
||||
REMOTE_AUTH_ENDPOINT: '//remote-auth-gateway.discord.gg',
|
||||
SENTRY_TAGS: { buildId: '9af39da', buildType: 'normal' },
|
||||
MIGRATION_SOURCE_ORIGIN: protocolRelative(data.apiEndpoint.replace(/\/api$/, '')),
|
||||
MIGRATION_DESTINATION_ORIGIN: protocolRelative(data.apiEndpoint.replace(/\/api$/, '')),
|
||||
MIGRATION_SOURCE_ORIGIN: protocolRelative(data.api.baseUrl),
|
||||
MIGRATION_DESTINATION_ORIGIN: protocolRelative(data.api.baseUrl),
|
||||
HTML_TIMESTAMP: Date.now(),
|
||||
ALGOLIA_KEY: 'aca0d7082e4e63af5ba5917d5e96bed0',
|
||||
GATEWAY_URL: data.gateway
|
||||
|
||||
BIN
package-lock.json
generated
BIN
package-lock.json
generated
Binary file not shown.
@ -75,6 +75,7 @@
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.936.0",
|
||||
"@toondepauw/node-zstd": "^1.2.0",
|
||||
"@types/web-push": "^3.6.4",
|
||||
"ajv": "^8.17.1",
|
||||
"ajv-formats": "^3.0.1",
|
||||
"amqplib": "^0.10.9",
|
||||
@ -113,6 +114,7 @@
|
||||
"sqlite3": "^5.1.7",
|
||||
"tslib": "^2.8.1",
|
||||
"typeorm": "^0.3.27",
|
||||
"web-push": "^3.6.7",
|
||||
"wretch": "^2.11.1",
|
||||
"ws": "^8.18.3"
|
||||
},
|
||||
|
||||
@ -25,6 +25,7 @@ import path from "path";
|
||||
import express from "express";
|
||||
import { red } from "picocolors";
|
||||
import { initInstance } from "./util/handlers/Instance";
|
||||
import { configurePush } from "../util/util/WebPush";
|
||||
|
||||
const ASSETS_FOLDER = path.join(__dirname, "..", "..", "assets");
|
||||
const PUBLIC_ASSETS_FOLDER = path.join(ASSETS_FOLDER, "public");
|
||||
@ -57,6 +58,7 @@ export class SpacebarServer extends Server {
|
||||
await ConnectionConfig.init();
|
||||
await initInstance();
|
||||
WebAuthn.init();
|
||||
configurePush();
|
||||
|
||||
const logRequests = process.env["LOG_REQUESTS"] != undefined;
|
||||
if (logRequests) {
|
||||
@ -117,8 +119,6 @@ export class SpacebarServer extends Server {
|
||||
res.sendFile(path.join(ASSETS_FOLDER, "openapi.json"));
|
||||
});
|
||||
|
||||
app.use("*_", (req, res) => res.sendFile(path.join(PUBLIC_ASSETS_FOLDER, "index.html")));
|
||||
|
||||
// current well-known location (new commit 22 nov 2025 from spacebar)
|
||||
app.get("/.well-known/spacebar", (req, res) => {
|
||||
res.json({
|
||||
@ -155,6 +155,8 @@ export class SpacebarServer extends Server {
|
||||
});
|
||||
});
|
||||
|
||||
app.use("*_", (req, res) => res.sendFile(path.join(PUBLIC_ASSETS_FOLDER, "index.html")));
|
||||
|
||||
this.app.use(ErrorHandler);
|
||||
|
||||
ConnectionLoader.loadConnections();
|
||||
|
||||
0
src/api/routes/users/@me/devices/index.ts
Normal file
0
src/api/routes/users/@me/devices/index.ts
Normal file
@ -37,6 +37,7 @@ import {
|
||||
SecurityConfiguration,
|
||||
TemplateConfiguration,
|
||||
UserConfiguration,
|
||||
WebPushConfiguration,
|
||||
} from "../config";
|
||||
|
||||
export class ConfigValue {
|
||||
@ -58,7 +59,7 @@ export class ConfigValue {
|
||||
defaults: DefaultsConfiguration = new DefaultsConfiguration();
|
||||
external: ExternalTokensConfiguration = new ExternalTokensConfiguration();
|
||||
email: EmailConfiguration = new EmailConfiguration();
|
||||
passwordReset: PasswordResetConfiguration =
|
||||
new PasswordResetConfiguration();
|
||||
passwordReset: PasswordResetConfiguration = new PasswordResetConfiguration();
|
||||
user: UserConfiguration = new UserConfiguration();
|
||||
webPush: WebPushConfiguration = new WebPushConfiguration();
|
||||
}
|
||||
|
||||
24
src/util/config/types/WebPushConfiguration.ts
Normal file
24
src/util/config/types/WebPushConfiguration.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export class WebPushConfiguration {
|
||||
enabled: boolean = false;
|
||||
email: string | null = null;
|
||||
publicVapidKey: string | null = null;
|
||||
privateVapidKey: string | null = null;
|
||||
}
|
||||
@ -37,3 +37,4 @@ export * from "./SecurityConfiguration";
|
||||
export * from "./subconfigurations";
|
||||
export * from "./TemplateConfiguration";
|
||||
export * from "./UsersConfiguration";
|
||||
export * from "./WebPushConfiguration";
|
||||
|
||||
26
src/util/entities/PushSubscription.ts
Normal file
26
src/util/entities/PushSubscription.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { BaseClass } from "./BaseClass";
|
||||
import { User } from "./User";
|
||||
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn, RelationId } from "typeorm";
|
||||
|
||||
@Entity({ name: "push_subscriptions" })
|
||||
export class PushSubscription extends BaseClass {
|
||||
@Column({ type: "varchar", nullable: true })
|
||||
@RelationId((sub: PushSubscription) => sub.user)
|
||||
user_id: string;
|
||||
|
||||
@JoinColumn({ name: "user_id" })
|
||||
@ManyToOne(() => User, { onDelete: "SET NULL" })
|
||||
user: User;
|
||||
|
||||
@Column({ type: "varchar", nullable: false })
|
||||
endpoint: string;
|
||||
|
||||
@Column({ type: "bigint", nullable: true })
|
||||
expiration_time?: number;
|
||||
|
||||
@Column({ type: "varchar", nullable: false })
|
||||
auth: string;
|
||||
|
||||
@Column({ type: "varchar", nullable: false })
|
||||
p256dh: string;
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class PushSubscriptions1764870551028 implements MigrationInterface {
|
||||
name = "PushSubscriptions1764870551028";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE "push_subscriptions" (
|
||||
"id" character varying NOT NULL,
|
||||
"user_id" character varying,
|
||||
"endpoint" character varying NOT NULL,
|
||||
"expiration_time" bigint,
|
||||
"auth" character varying NOT NULL,
|
||||
"p256dh" character varying NOT NULL,
|
||||
CONSTRAINT "PK_push_subscriptions_id" PRIMARY KEY ("id"),
|
||||
CONSTRAINT "UQ_push_subscriptions_endpoint" UNIQUE ("endpoint")
|
||||
);
|
||||
`);
|
||||
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE "push_subscriptions"
|
||||
ADD CONSTRAINT "FK_push_subscriptions_user"
|
||||
FOREIGN KEY ("user_id") REFERENCES "users"("id")
|
||||
ON DELETE SET NULL ON UPDATE NO ACTION;
|
||||
`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE "push_subscriptions"
|
||||
DROP CONSTRAINT "FK_push_subscriptions_user";
|
||||
`);
|
||||
|
||||
await queryRunner.query(`DROP TABLE "push_subscriptions"`);
|
||||
}
|
||||
}
|
||||
35
src/util/util/WebPush.ts
Normal file
35
src/util/util/WebPush.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { Config } from "@spacebar/util";
|
||||
import { yellow } from "picocolors";
|
||||
import { PushSubscription } from "../entities/PushSubscription";
|
||||
import webpush, { PushSubscription as WebPushSubscription } from "web-push";
|
||||
|
||||
let vapidConfigured = false;
|
||||
|
||||
export function configurePush() {
|
||||
const { enabled, email, publicVapidKey, privateVapidKey } = Config.get().webPush;
|
||||
|
||||
if (!enabled) {
|
||||
vapidConfigured = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!email || !publicVapidKey || !privateVapidKey) {
|
||||
console.warn("[WebPush]", yellow("VAPID details are missing. Push notifications will be disabled."));
|
||||
vapidConfigured = false;
|
||||
return;
|
||||
}
|
||||
|
||||
webpush.setVapidDetails(email, publicVapidKey, privateVapidKey);
|
||||
vapidConfigured = true;
|
||||
}
|
||||
|
||||
export function parseSubscription(result: PushSubscription): WebPushSubscription {
|
||||
return {
|
||||
endpoint: result.endpoint,
|
||||
expirationTime: result.expiration_time ?? null,
|
||||
keys: {
|
||||
p256dh: result.p256dh,
|
||||
auth: result.auth,
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user