Problema CORS nel postare su Discourse da Obsidian

Ho iniziato a usare Obsidian per scrivere, quindi ho pensato di creare un plugin Obsidian per pubblicare sul mio forum Discourse. In teoria è facile da fare, ma la risposta del mio primo tentativo è stata:

Access to fetch at 'http://localhost:4200/posts.json' from origin 'app://obsidian.md' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

La richiesta viene effettuata dal client, ma il client è il dispositivo dell’utente. Se ho capito bene, questo è sicuro:

import DiscoursePlugin from "./main";
import { TFile } from "obsidian";

export async function publishToDiscourse(
	plugin: DiscoursePlugin,
	activeFile: TFile
): Promise<{ message: string }> {
	try {
		const content = await plugin.app.vault.read(activeFile);
		const baseUrl = plugin.settings.baseUrl;
		const apiKey = plugin.settings.apiKey;

		const headers = new Headers({
			"Content-Type": "application/json",
			"Api-Key": apiKey,
			"Api-Username": "scossar", // this needs to be a setting
		});
		const body = JSON.stringify({
			title: activeFile.name,
			raw: content, // TODO: parse the content to fix internal links
			category: 1, // this needs to be a setting
		});
		// TODO: check to see if the note has already been published
		const url = `${baseUrl}/posts.json`;

		const response = await fetch(url, { method: "POST", headers, body });

		if (!response.ok) {
			console.error("Error publishing to Discourse:", response.status);
			return { message: "Error publishing to Discourse" };
		}
        
		const jsonResponse = await response.json();
		// TODO: use the response to add a discoursePostId file property
		console.log(`jsonResponse: ${JSON.stringify(jsonResponse, null, 2)}`);
		return { message: "success" };
	} catch (error) {
		console.error("Error publishing to Discourse:", error);
		return { message: `Error: ${error.message}` };
	}
}

È possibile che ci sia una soluzione ovvia che mi sfugge. In caso contrario, c’è un modo in cui Discourse potrebbe permetterlo? Un plugin Discourse per Obsidian sembra che potrebbe essere utile. (Un’implementazione corretta sarebbe più complessa di quella che ho postato sopra.)

3 Mi Piace

Ero confuso all’inizio, ma capisco, hai configurato la tua app Obsidian con la tua chiave e solo tu hai accesso ad essa. Questo non sta accadendo in un browser, quindi le persone su Internet non hanno la tua chiave.

Ho un plugin Discourse che elabora moduli arbitrari (puoi usarlo su https://www.formhoster.com/). Volevo renderlo in grado di funzionare come l’utente corrente se l’utente era loggato al sito che elabora il modulo e ho riscontrato quello che penso sia lo stesso problema CORS e ho rinunciato abbastanza rapidamente. Il mio era in un browser piuttosto che in un’app come Obsidian, ma penso che il problema possa essere simile.

Tutto questo per dire che penso di non avere buone idee, ma spero che qualcun altro ne abbia. :person_shrugging:

1 Mi Piace

Giusto, Obsidian è un’app Electron che viene eseguita localmente. Utilizza l’archiviazione locale, quindi la chiave API rimane sul dispositivo dell’utente.

Si scopre che esiste una soluzione per il problema CORS. Finora l’ho testata solo sul mio computer desktop. Inoltre, Discourse è fantastico!

Il codice che ho postato sopra doveva essere modificato in:

import DiscoursePlugin from "./main";
import { requestUrl, TFile } from "obsidian";

//...

		const response = await requestUrl({
			url: url,
			method: "POST",
			contentType: "application/json",
			body,
			headers,
		});
//...

La prossima domanda riguarderà la possibilità per gli utenti di richiedere chiavi API utente dall’app, ma questo è un problema separato.

3 Mi Piace

È un plugin su cui stai lavorando? Ho un utente (e io stesso) che adorerebbe poterlo usare. Posso provare a ricreare quello che hai fatto, ma se c’è un modo più semplice…

È stato l’inizio di qualcosa. Per i miei scopi sono più interessato a un’applicazione CLI (command line) che consenta di sincronizzare una Obsidian Vault con un forum Discourse. Un’app CLI rende più facile gestire la sincronizzazione di un’intera vault o sottodirectory, gestire collegamenti interni nelle Note, gestire caricamenti, ecc. L’approccio dell’app CLI si adatta anche ad altri lavori che sto facendo, quindi sto imparando qualcosa di utile da essa.

Il grande svantaggio dell’app CLI è che richiede a chiunque la utilizzi di avere Ruby installato sul proprio computer. Funzionerà anche solo su computer desktop. Ci sarebbero alcune sfide tecniche nell’utilizzarla su computer Windows.

Pubblicherò un link all’app qui una volta che sarà pronta per essere condivisa.

Se un plugin Obsidian Discourse, a differenza di un’app CLI, è qualcosa che interessa alle persone, lo esaminerò di nuovo in futuro. È possibile che qualcun altro ci arrivi prima di me. Non l’ho portato molto oltre l’esempio di codice postato sopra.

1 Mi Piace

Se questo è tutto ciò che hai finora, sembra abbastanza semplice. Mi chiedo come gestirebbe le immagini a questo punto. Sarei disposto a provarci. Non ho mai scritto un plugin per Obsidian prima, ma da quello che ho visto (fugaci occhiate ad altri plugin), non sembra terribilmente complicato.

1 Mi Piace

Questo è il posto giusto per iniziare: Build a plugin - Developer Documentation. Mi piacerebbe linkare a quello che ho fatto, ma è uno dei pochi (spero unici) progetti che non ho caricato su Github prima di reinstallare il sistema operativo sul mio computer la scorsa settimana.

Dovrai capire come farlo con Node. C’è un buon esempio in Ruby qui: discourse_api/examples/upload_file.rb at main · discourse/discourse_api · GitHub. Chiama: discourse_api/lib/discourse_api/api/uploads.rb at main · discourse/discourse_api · GitHub.

Puoi condividere questa parte?

Hmm, perdere quel codice è stato piuttosto sconsiderato. A memoria, stavo importando DiscoursePlugin definito in main.ts in un file che gestiva una chiamata a this.addCommand. Per iniziare, puoi fare tutto in main.ts. Seguirei semplicemente la guida per iniziare con il plugin di esempio. Inizia a sperimentare e a cercare di fare in modo che succeda qualcosa. So che ho usato quel plugin come modello per il mio.

Ci sono anche alcuni buoni esempi qui: obsidian-wordpress/src at main · devbean/obsidian-wordpress · GitHub.

1 Mi Piace

Bene, per ora metto da parte questa cosa. Ho fatto buoni progressi, ma ci sono alcune cose che non mi piacciono.

  • La chiave API è memorizzata in testo normale (MOLTO MALE)
  • le immagini non vengono caricate, ci sono alcune impostazioni di configurazione che non ho ancora esplorato. Ma non mi piace configurare un bucket AWS S3. Ci guarderò più tardi.
  • alcune scelte stilistiche potrebbero essere migliori, ma volevo qualcosa di funzionale
  • Il README deve essere aggiornato. Ma, di nuovo, volevo solo qualcosa di funzionale e pubblicato.
1 Mi Piace

Mi chiedo se ci sia un modo per aggirare questo problema. Nell’app CLI la crittografo con una password. L’utente deve fornire la password prima di qualsiasi operazione che utilizzi la chiave API.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.