Merge pull request #39 from movie-web/dev

Backend update v1.3.1
This commit is contained in:
William Oldham 2024-01-25 21:34:41 +00:00 committed by GitHub
commit f4b3d43b8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 52 additions and 36 deletions

View File

@ -41,7 +41,7 @@ services:
links:
- postgres:postgres
environment:
- DATABASE_URL=postgres://postgres:postgres@postgres:5432/postgres?sslmode=disable
- PGWEB_DATABASE_URL=postgres://postgres:postgres@postgres:5432/postgres?sslmode=disable
depends_on:
- postgres

4
.github/CODEOWNERS vendored
View File

@ -1,3 +1 @@
* @movie-web/core
.github @binaryoverload
* @movie-web/project-leads

View File

@ -14,16 +14,16 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- name: Install Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18
node-version: 20
cache: 'pnpm'
- name: Install packages
@ -38,16 +38,16 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- name: Install Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18
node-version: 20
cache: 'pnpm'
- name: Install packages
@ -62,10 +62,10 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Build
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5

View File

@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Get version
id: package-version
@ -42,10 +42,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Get version
id: package-version
@ -70,9 +70,12 @@ jobs:
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
with:
push: true
platforms: linux/amd64,linux/arm64
context: .
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max

View File

@ -1,6 +1,6 @@
{
"name": "backend",
"version": "1.3.0",
"version": "1.3.1",
"private": true,
"homepage": "https://github.com/movie-web/backend",
"engines": {

View File

@ -2,6 +2,7 @@ import { devFragment } from '@/config/fragments/dev';
import { dockerFragment } from '@/config/fragments/docker';
import { createConfigLoader } from 'neat-config';
import { z } from 'zod';
import { booleanSchema } from './schema';
const fragments = {
dev: devFragment,
@ -13,7 +14,7 @@ export const ormConfigSchema = z.object({
// connection URL for postgres database
connection: z.string(),
// whether to use SSL for the connection
ssl: z.coerce.boolean().default(false),
ssl: booleanSchema.default(false),
}),
});

View File

@ -1,5 +1,7 @@
import { z } from 'zod';
export const booleanSchema = z.preprocess((val) => val === 'true', z.boolean());
export const configSchema = z.object({
server: z
.object({
@ -11,13 +13,13 @@ export const configSchema = z.object({
// disable cross origin restrictions, allow any site.
// overwrites the cors option above
allowAnySite: z.coerce.boolean().default(false),
allowAnySite: booleanSchema.default(false),
// should it trust reverse proxy headers? (for ip gathering)
trustProxy: z.coerce.boolean().default(false),
trustProxy: booleanSchema.default(false),
// should it trust cloudflare headers? (for ip gathering, cloudflare has priority)
trustCloudflare: z.coerce.boolean().default(false),
trustCloudflare: booleanSchema.default(false),
// prefix for where the instance is run on. for example set it to /backend if you're hosting it on example.com/backend
// if this is set, do not apply url rewriting before proxing
@ -30,7 +32,7 @@ export const configSchema = z.object({
format: z.enum(['json', 'pretty']).default('pretty'),
// show debug logs?
debug: z.coerce.boolean().default(false),
debug: booleanSchema.default(false),
})
.default({}),
postgres: z.object({
@ -38,19 +40,19 @@ export const configSchema = z.object({
connection: z.string(),
// run all migrations on boot of the application
migrateOnBoot: z.coerce.boolean().default(false),
migrateOnBoot: booleanSchema.default(false),
// try to sync the schema on boot, useful for development
// will always keep the database schema in sync with the connected database
// it is extremely destructive, do not use it EVER in production
syncSchema: z.coerce.boolean().default(false),
syncSchema: booleanSchema.default(false),
// Enable debug logging for MikroORM - Outputs queries and entity management logs
// Do NOT use in production, leaks all sensitive data
debugLogging: z.coerce.boolean().default(false),
debugLogging: booleanSchema.default(false),
// Enable SSL for the postgres connection
ssl: z.coerce.boolean().default(false),
ssl: booleanSchema.default(false),
}),
crypto: z.object({
// session secret. used for signing session tokens
@ -65,7 +67,7 @@ export const configSchema = z.object({
captcha: z
.object({
// enabled captchas on register
enabled: z.coerce.boolean().default(false),
enabled: booleanSchema.default(false),
// captcha secret
secret: z.string().min(1).optional(),
@ -76,7 +78,7 @@ export const configSchema = z.object({
ratelimits: z
.object({
// enabled captchas on register
enabled: z.coerce.boolean().default(false),
enabled: booleanSchema.default(false),
redisUrl: z.string().optional(),
})
.default({}),

View File

@ -13,6 +13,7 @@ export type Metrics = {
providerHostnames: Counter<'hostname'>;
providerStatuses: Counter<'provider_id' | 'status'>;
watchMetrics: Counter<'title' | 'tmdb_full_id' | 'provider_id' | 'success'>;
toolMetrics: Counter<'tool'>;
};
let metrics: null | Metrics = null;
@ -59,6 +60,11 @@ export async function setupMetrics(app: FastifyInstance) {
help: 'mw_media_watch_count',
labelNames: ['title', 'tmdb_full_id', 'provider_id', 'success'],
}),
toolMetrics: new Counter({
name: 'mw_provider_tool_count',
help: 'mw_provider_tool_count',
labelNames: ['tool'],
}),
};
const promClient = app.metrics.client;
@ -68,6 +74,7 @@ export async function setupMetrics(app: FastifyInstance) {
promClient.register.registerMetric(metrics.providerStatuses);
promClient.register.registerMetric(metrics.watchMetrics);
promClient.register.registerMetric(metrics.captchaSolves);
promClient.register.registerMetric(metrics.toolMetrics);
const orm = getORM();
const em = orm.em.fork();

View File

@ -19,6 +19,7 @@ const metricsProviderSchema = z.object({
const metricsProviderInputSchema = z.object({
items: z.array(metricsProviderSchema).max(10).min(1),
tool: z.string().optional(),
});
export const metricsRouter = makeRouter((app) => {
@ -65,6 +66,12 @@ export const metricsRouter = makeRouter((app) => {
});
}
if (body.tool) {
getMetrics().toolMetrics.inc({
tool: body.tool,
});
}
return true;
}),
);

View File

@ -4,16 +4,14 @@ import { StatusError } from '@/services/error';
export async function isValidCaptcha(token: string): Promise<boolean> {
if (!conf.captcha.secret)
throw new Error('isValidCaptcha() is called but no secret set');
const formData = new URLSearchParams();
formData.append('secret', conf.captcha.secret);
formData.append('response', token);
const res = await fetch('https://www.google.com/recaptcha/api/siteverify', {
method: 'POST',
body: JSON.stringify({
secret: conf.captcha.secret,
response: token,
}),
headers: {
'content-type': 'application/json',
},
body: formData,
});
const json = await res.json();
return !!json.success;
}