2026-07-19 00:29:30 +08:00
import { NextResponse } from "next/server" ;
import { requireUser } from "@/lib/auth" ;
import { db } from "@/lib/db" ;
2026-07-19 05:55:43 +08:00
import { decrypt , encrypt } from "@/lib/crypto" ;
import { createUserWebhook , deleteUserWebhook , getMemosIdentity } from "@/lib/memos" ;
2026-07-19 00:29:30 +08:00
import { createWebhookSecret , webhookSecretHash } from "@/lib/webhook" ;
2026-07-19 03:58:03 +08:00
import { requireSameOrigin } from "@/lib/security" ;
2026-07-19 00:29:30 +08:00
export async function POST ( request : Request , { params } : { params : Promise < { id : string } > }) {
try {
2026-07-19 03:58:03 +08:00
requireSameOrigin ( request ); const user = await requireUser (); const { id : rawId } = await params ; const id = Number ( rawId );
2026-07-19 05:55:43 +08:00
const source = db . prepare ( "SELECT id,base_url,token_encrypted,remote_user,webhook_mode,webhook_remote_name FROM sources WHERE id=? AND user_id=?" ). get ( id , user . id ) as { id : number ; base_url : string ; token_encrypted : string ; remote_user : string | null ; webhook_mode : string ; webhook_remote_name : string | null } | undefined ;
2026-07-19 00:29:30 +08:00
if ( ! source ) return NextResponse . json ({ error : "Not found" }, { status : 404 });
2026-07-19 05:55:43 +08:00
if ( source . webhook_mode === "signed" ) {
const token = decrypt ( source . token_encrypted ); const identity = source . remote_user ? { name : source.remote_user } : await getMemosIdentity ( source . base_url , token ); const pathSecret = createWebhookSecret (); const signingSecret = createWebhookSecret (); const publicOrigin = ( process . env . NEXT_PUBLIC_APP_URL || new URL ( request . url ). origin ). replace ( /\/$/ , "" );
const remote = await createUserWebhook ( source . base_url , token , identity . name , { url : ` ${ publicOrigin } /api/sync/webhook/ ${ id } / ${ pathSecret } ` , displayName : "Mebbling" , signingSecret });
try { if ( source . webhook_remote_name ) await deleteUserWebhook ( source . base_url , token , identity . name , source . webhook_remote_name ); }
catch ( error ) { try { await deleteUserWebhook ( source . base_url , token , identity . name , remote . name ); } catch {} throw error ; }
db . prepare ( "UPDATE sources SET webhook_secret_hash=?,webhook_remote_name=?,webhook_signing_secret_encrypted=? WHERE id=?" ). run ( webhookSecretHash ( pathSecret ), remote . name , encrypt ( signingSecret ), id );
return NextResponse . json ({ rotated : true });
}
2026-07-19 00:29:30 +08:00
const secret = createWebhookSecret ();
db . prepare ( "UPDATE sources SET webhook_secret_hash=? WHERE id=?" ). run ( webhookSecretHash ( secret ), id );
const publicOrigin = ( process . env . NEXT_PUBLIC_APP_URL || new URL ( request . url ). origin ). replace ( /\/$/ , "" );
return NextResponse . json ({ url : ` ${ publicOrigin } /api/sync/webhook/ ${ id } / ${ secret } ` });
} catch { return NextResponse . json ({ error : "Unauthorized" }, { status : 401 }); }
}