fix: swagger CSP issue (#1284)
This commit is contained in:
parent
32a82ad565
commit
12b037e2cb
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,6 +11,7 @@ build
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
electron/renderer
|
electron/renderer
|
||||||
electron/models
|
electron/models
|
||||||
|
electron/docs
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@ -148,19 +148,19 @@ Contributions are welcome! Please read the [CONTRIBUTING.md](CONTRIBUTING.md) fi
|
|||||||
|
|
||||||
1. **Clone the repository and prepare:**
|
1. **Clone the repository and prepare:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/janhq/jan
|
git clone https://github.com/janhq/jan
|
||||||
cd jan
|
cd jan
|
||||||
git checkout -b DESIRED_BRANCH
|
git checkout -b DESIRED_BRANCH
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Run development and use Jan Desktop**
|
2. **Run development and use Jan Desktop**
|
||||||
|
|
||||||
```
|
```bash
|
||||||
make dev
|
make dev
|
||||||
```
|
```
|
||||||
|
|
||||||
This will start the development server and open the desktop app.
|
This will start the development server and open the desktop app.
|
||||||
|
|
||||||
### For production build
|
### For production build
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,8 @@ export enum AppRoute {
|
|||||||
relaunch = 'relaunch',
|
relaunch = 'relaunch',
|
||||||
joinPath = 'joinPath',
|
joinPath = 'joinPath',
|
||||||
baseName = 'baseName',
|
baseName = 'baseName',
|
||||||
|
startServer = 'startServer',
|
||||||
|
stopServer = 'stopServer',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AppEvent {
|
export enum AppEvent {
|
||||||
|
|||||||
0
electron/docs/openapi/.gitkeep
Normal file
0
electron/docs/openapi/.gitkeep
Normal file
@ -1,9 +1,10 @@
|
|||||||
import { app, ipcMain, shell, nativeTheme } from 'electron'
|
import { app, ipcMain, shell, nativeTheme } from 'electron'
|
||||||
import { join, basename } from 'path'
|
import { join, basename } from 'path'
|
||||||
import { WindowManager } from './../managers/window'
|
import { WindowManager } from './../managers/window'
|
||||||
import { userSpacePath } from './../utils/path'
|
import { getResourcePath, userSpacePath } from './../utils/path'
|
||||||
import { AppRoute } from '@janhq/core'
|
import { AppRoute } from '@janhq/core'
|
||||||
import { ExtensionManager, ModuleManager } from '@janhq/core/node'
|
import { ExtensionManager, ModuleManager } from '@janhq/core/node'
|
||||||
|
import { startServer, stopServer } from '@janhq/server'
|
||||||
|
|
||||||
export function handleAppIPCs() {
|
export function handleAppIPCs() {
|
||||||
/**
|
/**
|
||||||
@ -56,6 +57,23 @@ export function handleAppIPCs() {
|
|||||||
basename(path)
|
basename(path)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start Jan API Server.
|
||||||
|
*/
|
||||||
|
ipcMain.handle(AppRoute.startServer, async (_event) =>
|
||||||
|
startServer(
|
||||||
|
app.isPackaged
|
||||||
|
? join(getResourcePath(), 'docs', 'openapi', 'jan.yaml')
|
||||||
|
: undefined,
|
||||||
|
app.isPackaged ? join(getResourcePath(), 'docs', 'openapi') : undefined
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop Jan API Server.
|
||||||
|
*/
|
||||||
|
ipcMain.handle(AppRoute.stopServer, async (_event) => stopServer())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Relaunches the app in production - reload window in development.
|
* Relaunches the app in production - reload window in development.
|
||||||
* @param _event - The IPC event object.
|
* @param _event - The IPC event object.
|
||||||
|
|||||||
@ -20,11 +20,6 @@ import { handleAppUpdates } from './handlers/update'
|
|||||||
import { handleFsIPCs } from './handlers/fs'
|
import { handleFsIPCs } from './handlers/fs'
|
||||||
import { migrateExtensions } from './utils/migration'
|
import { migrateExtensions } from './utils/migration'
|
||||||
|
|
||||||
/**
|
|
||||||
* Server
|
|
||||||
*/
|
|
||||||
import { startServer } from '@janhq/server'
|
|
||||||
|
|
||||||
app
|
app
|
||||||
.whenReady()
|
.whenReady()
|
||||||
.then(createUserSpace)
|
.then(createUserSpace)
|
||||||
@ -34,7 +29,6 @@ app
|
|||||||
.then(handleIPCs)
|
.then(handleIPCs)
|
||||||
.then(handleAppUpdates)
|
.then(handleAppUpdates)
|
||||||
.then(createMainWindow)
|
.then(createMainWindow)
|
||||||
.then(startServer)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
if (!BrowserWindow.getAllWindows().length) {
|
if (!BrowserWindow.getAllWindows().length) {
|
||||||
|
|||||||
@ -14,11 +14,13 @@
|
|||||||
"build/*.{js,map}",
|
"build/*.{js,map}",
|
||||||
"build/**/*.{js,map}",
|
"build/**/*.{js,map}",
|
||||||
"pre-install",
|
"pre-install",
|
||||||
"models/**/*"
|
"models/**/*",
|
||||||
|
"docs/**/*"
|
||||||
],
|
],
|
||||||
"asarUnpack": [
|
"asarUnpack": [
|
||||||
"pre-install",
|
"pre-install",
|
||||||
"models"
|
"models",
|
||||||
|
"docs"
|
||||||
],
|
],
|
||||||
"publish": [
|
"publish": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -25,7 +25,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "yarn workspace jan lint && yarn workspace jan-web lint",
|
"lint": "yarn workspace jan lint && yarn workspace jan-web lint",
|
||||||
"test": "yarn workspace jan test:e2e",
|
"test": "yarn workspace jan test:e2e",
|
||||||
"dev:electron": "cpx \"models/**\" \"electron/models/\" && yarn workspace jan dev",
|
"copy:assets": "cpx \"models/**\" \"electron/models/\" && cpx \"docs/openapi/**\" \"electron/docs/openapi\"",
|
||||||
|
"dev:electron": "yarn copy:assets && yarn workspace jan dev",
|
||||||
"dev:web": "yarn workspace jan-web dev",
|
"dev:web": "yarn workspace jan-web dev",
|
||||||
"dev": "concurrently --kill-others \"yarn dev:web\" \"wait-on http://localhost:3000 && yarn dev:electron\"",
|
"dev": "concurrently --kill-others \"yarn dev:web\" \"wait-on http://localhost:3000 && yarn dev:electron\"",
|
||||||
"test-local": "yarn lint && yarn build:test && yarn test",
|
"test-local": "yarn lint && yarn build:test && yarn test",
|
||||||
@ -34,15 +35,15 @@
|
|||||||
"build:server": "cd server && yarn install && yarn run build",
|
"build:server": "cd server && yarn install && yarn run build",
|
||||||
"build:core": "cd core && yarn install && yarn run build",
|
"build:core": "cd core && yarn install && yarn run build",
|
||||||
"build:web": "yarn workspace jan-web build && cpx \"web/out/**\" \"electron/renderer/\"",
|
"build:web": "yarn workspace jan-web build && cpx \"web/out/**\" \"electron/renderer/\"",
|
||||||
"build:electron": "cpx \"models/**\" \"electron/models/\" && yarn workspace jan build",
|
"build:electron": "yarn copy:assets && yarn workspace jan build",
|
||||||
"build:electron:test": "yarn workspace jan build:test",
|
"build:electron:test": "yarn workspace jan build:test",
|
||||||
"build:extensions:windows": "rimraf ./electron/pre-install/*.tgz && powershell -command \"$jobs = Get-ChildItem -Path './extensions' -Directory | ForEach-Object { Start-Job -Name ($_.Name) -ScriptBlock { param($_dir); try { Set-Location $_dir; npm install; npm run build:publish; Write-Output 'Build successful in ' + $_dir } catch { Write-Error 'Error in ' + $_dir; throw } } -ArgumentList $_.FullName }; $jobs | Wait-Job; $jobs | ForEach-Object { Receive-Job -Job $_ -Keep } | ForEach-Object { Write-Host $_ }; $failed = $jobs | Where-Object { $_.State -ne 'Completed' -or $_.ChildJobs[0].JobStateInfo.State -ne 'Completed' }; if ($failed) { Exit 1 }\"",
|
"build:extensions:windows": "rimraf ./electron/pre-install/*.tgz && powershell -command \"$jobs = Get-ChildItem -Path './extensions' -Directory | ForEach-Object { Start-Job -Name ($_.Name) -ScriptBlock { param($_dir); try { Set-Location $_dir; npm install; npm run build:publish; Write-Output 'Build successful in ' + $_dir } catch { Write-Error 'Error in ' + $_dir; throw } } -ArgumentList $_.FullName }; $jobs | Wait-Job; $jobs | ForEach-Object { Receive-Job -Job $_ -Keep } | ForEach-Object { Write-Host $_ }; $failed = $jobs | Where-Object { $_.State -ne 'Completed' -or $_.ChildJobs[0].JobStateInfo.State -ne 'Completed' }; if ($failed) { Exit 1 }\"",
|
||||||
"build:extensions:linux": "rimraf ./electron/pre-install/*.tgz && find ./extensions -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -n 1 -P 4 -I {} sh -c 'cd {} && npm install && npm run build:publish'",
|
"build:extensions:linux": "rimraf ./electron/pre-install/*.tgz && find ./extensions -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -n 1 -P 4 -I {} sh -c 'cd {} && npm install && npm run build:publish'",
|
||||||
"build:extensions:darwin": "rimraf ./electron/pre-install/*.tgz && find ./extensions -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -n 1 -P 4 -I {} sh -c 'cd {} && npm install && npm run build:publish'",
|
"build:extensions:darwin": "rimraf ./electron/pre-install/*.tgz && find ./extensions -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -n 1 -P 4 -I {} sh -c 'cd {} && npm install && npm run build:publish'",
|
||||||
"build:extensions": "run-script-os",
|
"build:extensions": "run-script-os",
|
||||||
"build:test": "yarn build:web && yarn workspace jan build:test",
|
"build:test": "yarn copy:assets && yarn build:web && yarn workspace jan build:test",
|
||||||
"build": "yarn build:web && yarn build:electron",
|
"build": "yarn build:web && yarn build:electron",
|
||||||
"build:publish": "cpx \"models/**\" \"electron/models/\" && yarn build:web && yarn workspace jan build:publish"
|
"build:publish": "yarn copy:assets && yarn build:web && yarn workspace jan build:publish"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^8.2.1",
|
"concurrently": "^8.2.1",
|
||||||
|
|||||||
@ -2,33 +2,61 @@ import fastify from "fastify";
|
|||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import { v1Router } from "@janhq/core/node";
|
import { v1Router } from "@janhq/core/node";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
import fs from "fs";
|
||||||
|
import util from "util";
|
||||||
|
import os from "os";
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
const JAN_API_HOST = process.env.JAN_API_HOST || "0.0.0.0";
|
const JAN_API_HOST = process.env.JAN_API_HOST || "127.0.0.1";
|
||||||
const JAN_API_PORT = Number.parseInt(process.env.JAN_API_PORT || "1337");
|
const JAN_API_PORT = Number.parseInt(process.env.JAN_API_PORT || "1337");
|
||||||
|
const serverLogPath = path.join(os.homedir(), "jan", "server.log");
|
||||||
|
|
||||||
const server = fastify();
|
let server: any | undefined = undefined;
|
||||||
server.register(require("@fastify/cors"), {});
|
|
||||||
server.register(require("@fastify/swagger"), {
|
var log_file = fs.createWriteStream(serverLogPath, {
|
||||||
|
flags: "a",
|
||||||
|
});
|
||||||
|
var log_stdout = process.stdout;
|
||||||
|
var log_stderr = process.stderr;
|
||||||
|
|
||||||
|
const logServer = function (d: any) {
|
||||||
|
log_file.write(util.format(d) + "\n");
|
||||||
|
log_stdout.write(util.format(d) + "\n");
|
||||||
|
log_stderr.write(util.format(d) + "\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
export const startServer = async (schemaPath?: string, baseDir?: string) => {
|
||||||
|
try {
|
||||||
|
server = fastify({
|
||||||
|
logger: {
|
||||||
|
level: "info",
|
||||||
|
file: serverLogPath,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await server.register(require("@fastify/cors"), {});
|
||||||
|
|
||||||
|
await server.register(require("@fastify/swagger"), {
|
||||||
mode: "static",
|
mode: "static",
|
||||||
specification: {
|
specification: {
|
||||||
path: "./../docs/openapi/jan.yaml",
|
path: schemaPath ?? "./../docs/openapi/jan.yaml",
|
||||||
baseDir: "./../docs/openapi",
|
baseDir: baseDir ?? "./../docs/openapi",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
server.register(require("@fastify/swagger-ui"), {
|
|
||||||
|
await server.register(require("@fastify/swagger-ui"), {
|
||||||
routePrefix: "/docs",
|
routePrefix: "/docs",
|
||||||
baseDir: path.join(__dirname, "../..", "./docs/openapi"),
|
baseDir: baseDir ?? path.join(__dirname, "../..", "./docs/openapi"),
|
||||||
uiConfig: {
|
uiConfig: {
|
||||||
docExpansion: "full",
|
docExpansion: "full",
|
||||||
deepLinking: false,
|
deepLinking: false,
|
||||||
},
|
},
|
||||||
staticCSP: true,
|
staticCSP: false,
|
||||||
transformSpecificationClone: true,
|
transformSpecificationClone: true,
|
||||||
});
|
});
|
||||||
server.register(
|
|
||||||
(childContext, _, done) => {
|
await server.register(
|
||||||
|
(childContext: any, _: any, done: any) => {
|
||||||
childContext.register(require("@fastify/static"), {
|
childContext.register(require("@fastify/static"), {
|
||||||
root:
|
root:
|
||||||
process.env.EXTENSION_ROOT ||
|
process.env.EXTENSION_ROOT ||
|
||||||
@ -39,22 +67,27 @@ server.register(
|
|||||||
done();
|
done();
|
||||||
},
|
},
|
||||||
{ prefix: "extensions" }
|
{ prefix: "extensions" }
|
||||||
);
|
);
|
||||||
server.register(v1Router, { prefix: "/v1" });
|
await server.register(v1Router, { prefix: "/v1" });
|
||||||
|
await server
|
||||||
export const startServer = () => {
|
|
||||||
server
|
|
||||||
.listen({
|
.listen({
|
||||||
port: JAN_API_PORT,
|
port: JAN_API_PORT,
|
||||||
host: JAN_API_HOST,
|
host: JAN_API_HOST,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log(
|
logServer(
|
||||||
`JAN API listening at: http://${JAN_API_HOST}:${JAN_API_PORT}`
|
`JAN API listening at: http://${JAN_API_HOST}:${JAN_API_PORT}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
} catch (e) {
|
||||||
|
logServer(e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const stopServer = () => {
|
export const stopServer = async () => {
|
||||||
server.close();
|
try {
|
||||||
|
await server.close();
|
||||||
|
} catch (e) {
|
||||||
|
logServer(e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -11,19 +11,23 @@ import {
|
|||||||
ModalHeader,
|
ModalHeader,
|
||||||
ModalTitle,
|
ModalTitle,
|
||||||
ModalTrigger,
|
ModalTrigger,
|
||||||
Badge,
|
|
||||||
} from '@janhq/uikit'
|
} from '@janhq/uikit'
|
||||||
|
|
||||||
|
import { atom, useAtom } from 'jotai'
|
||||||
|
|
||||||
import ShortCut from '@/containers/Shortcut'
|
import ShortCut from '@/containers/Shortcut'
|
||||||
|
|
||||||
import { FeatureToggleContext } from '@/context/FeatureToggle'
|
import { FeatureToggleContext } from '@/context/FeatureToggle'
|
||||||
|
|
||||||
import { useSettings } from '@/hooks/useSettings'
|
import { useSettings } from '@/hooks/useSettings'
|
||||||
|
|
||||||
|
const serverEnabledAtom = atom<boolean>(false)
|
||||||
|
|
||||||
const Advanced = () => {
|
const Advanced = () => {
|
||||||
const { experimentalFeatureEnabed, setExperimentalFeatureEnabled } =
|
const { experimentalFeatureEnabed, setExperimentalFeatureEnabled } =
|
||||||
useContext(FeatureToggleContext)
|
useContext(FeatureToggleContext)
|
||||||
const [gpuEnabled, setGpuEnabled] = useState<boolean>(false)
|
const [gpuEnabled, setGpuEnabled] = useState<boolean>(false)
|
||||||
|
const [serverEnabled, setServerEnabled] = useAtom(serverEnabledAtom)
|
||||||
const { readSettings, saveSettings, validateSettings, setShowNotification } =
|
const { readSettings, saveSettings, validateSettings, setShowNotification } =
|
||||||
useSettings()
|
useSettings()
|
||||||
|
|
||||||
@ -87,6 +91,30 @@ const Advanced = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{/* Server */}
|
||||||
|
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||||
|
<div className="w-4/5 flex-shrink-0 space-y-1.5">
|
||||||
|
<div className="flex gap-x-2">
|
||||||
|
<h6 className="text-sm font-semibold capitalize">
|
||||||
|
Enable API Server
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
<p className="whitespace-pre-wrap leading-relaxed">
|
||||||
|
Enable API server for Jan app.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
checked={serverEnabled}
|
||||||
|
onCheckedChange={(e: boolean) => {
|
||||||
|
if (e === true) {
|
||||||
|
window.core?.api?.startServer()
|
||||||
|
} else {
|
||||||
|
window.core?.api?.stopServer()
|
||||||
|
}
|
||||||
|
setServerEnabled(e)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
{window.electronAPI && (
|
{window.electronAPI && (
|
||||||
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||||
<div className="w-4/5 flex-shrink-0 space-y-1.5">
|
<div className="w-4/5 flex-shrink-0 space-y-1.5">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user