feat(frontend): add impersonate api + local resolution of import by lsp v0

This commit is contained in:
Ruben Fiszel
2023-04-07 22:54:55 +02:00
parent 361ca33527
commit f940eab5de
11 changed files with 129 additions and 9 deletions
+58
View File
@@ -1048,6 +1048,27 @@ paths:
schema:
type: string
/users/tokens/impersonate:
post:
summary: create token to impersonate a user (require superadmin)
operationId: createTokenImpersonate
tags:
- user
requestBody:
description: new token
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/NewTokenImpersonate"
responses:
"201":
description: token created
content:
text/plain:
schema:
type: string
/users/tokens/delete/{token_prefix}:
delete:
summary: delete token
@@ -2344,6 +2365,24 @@ paths:
schema:
type: string
/scripts_u/tokened_raw/{workspace}/{token}/{path}:
get:
summary: raw script by path with a token (mostly used by lsp to be used with import maps to resolve scripts)
operationId: rawScriptByPathTokened
tags:
- script
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Token"
- $ref: "#/components/parameters/ScriptPath"
responses:
"200":
description: script content
content:
text/plain:
schema:
type: string
/w/{workspace}/scripts/exists/p/{path}:
get:
summary: exists script by path
@@ -4535,6 +4574,12 @@ components:
required: true
schema:
type: string
Token:
name: token
in: path
required: true
schema:
type: string
AccountId:
name: id
in: path
@@ -5132,6 +5177,19 @@ components:
type: string
format: date-time
NewTokenImpersonate:
type: object
properties:
label:
type: string
expiration:
type: string
format: date-time
impersonate_email:
type: string
required:
- impersonate_email
ListableVariable:
type: object
properties:
+1
View File
@@ -149,6 +149,7 @@ pub async fn run_server(
.nest("/schedules", schedule::global_service())
.route_layer(from_extractor::<Authed>())
.route_layer(from_extractor::<users::Tokened>())
.nest("/scripts_u", scripts::global_unauthed_service())
.nest(
"/w/:workspace_id/apps_u",
apps::unauthed_service()
+21 -1
View File
@@ -13,7 +13,7 @@ use windmill_parser::MainArgSignature;
use crate::{
db::{UserDB, DB},
schedule::clear_schedule,
users::{maybe_refresh_folders, require_owner_of_path, Authed},
users::{maybe_refresh_folders, require_owner_of_path, AuthCache, Authed},
webhook_util::{WebhookMessage, WebhookShared},
HTTP_CLIENT,
};
@@ -30,6 +30,7 @@ use sqlx::{FromRow, Postgres, Transaction};
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
sync::Arc,
};
use windmill_common::{
error::{Error, JsonResult, Result},
@@ -61,6 +62,13 @@ pub fn global_service() -> Router {
.route("/hub/get_full/*path", get(get_full_hub_script_by_path))
}
pub fn global_unauthed_service() -> Router {
Router::new().route(
"/tokened_raw/:workspace/:token/*path",
get(get_tokened_raw_script_by_path),
)
}
pub fn workspaced_service() -> Router {
Router::new()
.route("/list", get(list_scripts))
@@ -498,6 +506,18 @@ async fn list_paths(
Ok(Json(scripts))
}
async fn get_tokened_raw_script_by_path(
Extension(user_db): Extension<UserDB>,
Path((w_id, token, path)): Path<(String, String, StripPath)>,
Extension(cache): Extension<Arc<AuthCache>>,
) -> Result<String> {
let authed = cache
.get_authed(Some(w_id.clone()), &token)
.await
.ok_or_else(|| Error::NotAuthorized("Invalid token".to_string()))?;
return raw_script_by_path(authed, Extension(user_db), Path((w_id, path))).await;
}
async fn raw_script_by_path(
authed: Authed,
Extension(user_db): Extension<UserDB>,
+1
View File
@@ -7,5 +7,6 @@ http://localhost {
https://localhost {
bind {$ADDRESS}
reverse_proxy /api/* http://localhost:8000
reverse_proxy /ws/* http://localhost:3001
}
+44 -6
View File
@@ -37,7 +37,6 @@
import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc'
import { CloseAction, ErrorAction, RequestType } from 'vscode-languageclient'
import * as vscode from 'vscode'
languages.typescript.typescriptDefaults.setModeConfiguration({
completionItems: false,
definitions: false,
@@ -71,19 +70,21 @@
import type { DocumentUri, MessageTransports } from 'vscode-languageclient'
import { dirtyStore } from './common/confirmationModal/dirtyStore'
import { buildWorkerDefinition } from './build_workers'
import { workspaceStore } from '$lib/stores'
import { UserService } from '$lib/gen'
let divEl: HTMLDivElement | null = null
let editor: meditor.IStandaloneCodeEditor
export let lang: 'typescript' | 'python' | 'go' | 'shell'
export let code: string = ''
export let hash: string = randomHash()
export let cmdEnterAction: (() => void) | undefined = undefined
export let formatAction: (() => void) | undefined = undefined
export let automaticLayout = true
export let websocketAlive = { pyright: false, black: false, deno: false, go: false }
export let shouldBindKey: boolean = true
export let fixedOverflowWidgets = true
export let path: string = randomHash()
let websockets: [MonacoLanguageClient, WebSocket][] = []
let websocketInterval: NodeJS.Timer | undefined
@@ -92,7 +93,8 @@
let disposeMethod: () => void | undefined
const dispatch = createEventDispatcher()
const uri = `file:///tmp/monaco/${hash}.${langToExt(lang)}`
const uri =
lang == 'go' ? `file:///tmp/monaco/${randomHash()}.go` : `file:///${path}.${langToExt(lang)}`
// if (lang != 'typescript') {
buildWorkerDefinition('../../../workers', import.meta.url, false)
@@ -286,6 +288,7 @@
command = vscode.commands.registerCommand(
'deno.cache',
(uris: DocumentUri[] = []) => {
console.log('cache', uris)
languageClient.sendRequest(new RequestType('deno/cache'), {
referrer: { uri },
uris: uris.map((uri) => ({ uri }))
@@ -306,6 +309,36 @@
const wsProtocol = $page.url.protocol == 'https:' ? 'wss' : 'ws'
if (lang == 'typescript') {
let expiration = new Date()
expiration.setHours(expiration.getHours() + 2)
const token = await UserService.createToken({
requestBody: { label: 'Ephemeral lsp token', expiration: expiration.toISOString() }
})
let root =
$page.url.protocol +
'//' +
$page.url.host +
'/api/scripts_u/tokened_raw/' +
$workspaceStore +
'/' +
token
const importMap = {
imports: {
'file:///': root + '/'
}
}
let path_splitted = path.split('/')
for (let c = 0; c < path_splitted.length; c++) {
let key = 'file://./'
for (let i = 0; i < c; i++) {
key += '../'
}
let url = path_splitted.slice(0, -c - 1).join('/')
let ending = c == path_splitted.length - 1 ? '' : '/'
importMap['imports'][key] = `${root}/${url}${ending}`
}
console.log(importMap)
const encodedImportMap = 'data:text/plain;base64,' + btoa(JSON.stringify(importMap))
await connectToLanguageServer(
`${wsProtocol}://${$page.url.host}/ws/deno`,
'deno',
@@ -313,7 +346,7 @@
certificateStores: null,
enablePaths: [],
config: null,
importMap: null,
importMap: encodedImportMap,
internalDebug: false,
lint: false,
path: null,
@@ -321,7 +354,6 @@
unsafelyIgnoreCertificateErrors: null,
unstable: true,
enable: true,
cache: null,
codeLens: {
implementations: true,
references: true,
@@ -340,7 +372,13 @@
}
}
},
undefined
() => {
return [
{
enable: true
}
]
}
)
} else if (lang === 'python') {
await connectToLanguageServer(
@@ -149,6 +149,7 @@
<div class="pl-2 h-full !overflow-visible">
{#key lang}
<Editor
{path}
bind:code
bind:websocketAlive
bind:this={editor}
@@ -216,6 +216,7 @@
<div class="border h-full">
{#if inlineScript.language != 'frontend'}
<Editor
path={inlineScript.path}
bind:this={editor}
class="flex flex-1 grow h-full"
lang={scriptLangToEditorLang(inlineScript?.language)}
@@ -180,6 +180,7 @@
<Pane size={isScript ? 30 : 50} minSize={20}>
{#if value.type === 'rawscript'}
<Editor
path={value['path']}
bind:websocketAlive
bind:this={editor}
class="h-full relative"
File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

+1 -1
View File
@@ -30,6 +30,7 @@ class LanguageServerWebSocketHandler(websocket.WebSocketHandler):
# Create an instance of the language server
self.proc = process.Subprocess(
self.procargs,
env=os.environ,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
)
@@ -85,7 +86,6 @@ class MainHandler(web.RequestHandler):
if __name__ == "__main__":
monaco_path = "/tmp/monaco"
os.makedirs(monaco_path, exist_ok=True)
print("The monaco directory is created!")