Compare commits

..

19 Commits

Author SHA1 Message Date
Sylvia Crowe ea253c33ae merge 'main' into use-ssh-library--add-user-input
I had to reimplement a few front end changes but nothing too major aside
from that.
2024-02-08 15:51:32 -08:00
Sylvia Crowe 53de138832 fix: add the userinput.tsx changes
These were missed in the previous commit. Adding them now.
2024-02-08 13:07:37 -08:00
Sylvia Crowe 75778963c5 merge 'main' into use-ssh-library--add-user-input
This merge is rather large, so it needs some explaining. Most of it was
a straightforward merge, but there were a few markdown edits i made that
had to manually be resolved.

There were also a few path changes to be made in the userinput.tsx file.
2024-02-08 13:06:56 -08:00
Sylvia Crowe 89906d21d4 feat: create naive ui for ssh key passphrases
This isn't quite as reactive as the other methods, but it does attempt
to use publickey without a passphrase, then attempt to use the password
as the passphrase, and finally prompting the user for a passphrase. The
problem with this approach is that if multiple keys are used and they
all have passphrases, they need to all be checked up front. In practice,
this will not happen often, but it is something to be aware of.
2024-02-08 02:53:37 -08:00
Sylvia Crowe 747a2b784a fix: set number of retries to two again
I was wrong in my previous analysis. The number given is the total
number of tries. This is confusing when keyboard authentication and
password authentication are both available which usually doesn't happen.
2024-02-07 17:03:08 -08:00
Sylvia Crowe 84e7605e36 refactor: change argument order in GetUserInput
This is a simple change to move the context to the first argument of
GetUserInput to match the convention used elsewhere in the code.
2024-02-07 17:01:35 -08:00
Sylvia Crowe 839e338dad fix: set number of retries to one in ssh
Number of retries means number of attempts after the fact, not number of
total attempts. It has been adjusted from 2 to 1 to reflect this.
2024-02-07 16:24:27 -08:00
Sylvia Crowe 771046637d fix: allow automatic and interactive auth together
Previously, it was impossible to use to separate methods of the same
type to try ssh authentication. This made it impossible to make an auto
attempt before a manual one. This change restricts that by combining
them into one method where the auto attempt is tried once first and
cannot be tried again. Following that, interactive authentication can be
tried separately.

It also lowers the time limit on kbd interactive authentication to 15
seconds due to limitations on the library we are using.
2024-02-07 16:00:39 -08:00
Sylvia Crowe 8dc3b3b0c1 feat: add interactive password authentication
This makes the ssh password authentication interactive with its own user
input modal. Unfortunately, this method does not allow trying a default
first. This will need to be expanded in the future to accomodate that.
2024-02-07 14:50:34 -08:00
Sylvia Crowe 0a8c8221fd feat: add user input for kbd-interactive auth
This adds a modal so the user can respond to prompts provided using the
keyboard interactive authentication method.
2024-02-06 21:34:33 -08:00
Sylvia Crowe 38c6e8f5f8 merge branch 'main' into use-ssh-library--add-user-input 2024-02-05 16:36:15 -08:00
Sylvia Crowe def90a0493 feat: allow writing to known_hosts first pass
As a follow-up to the previous change, we now allow the user to respond
to interactive queries in order to determine if an unknown known hosts
key can be added to a known_hosts file if it is missing. This needs to
be refined further, but it gets the basic functionality there.
2024-02-05 16:26:54 -08:00
Sylvia Crowe e2d10cd807 feat: create first pass known_hosts detection
Manually integrating with golang's ssh library means that the code must
authenticate known_hosts on its own. This is a first pass at creating a
system that parses the known hosts files and denys a connection if there
is a mismatch. This needs to be updated with a means to add keys to the
known-hosts file if the user requests it.
2024-02-02 11:50:02 -08:00
Sylvia Crowe 26240bea97 feat: complete user input modal
This rounds out the most immediate concerns for the new user input
modal. The frontend now includes a timer to show how much time is left
and will close itself once it reaches zero. Css
formatting has been cleaned up to be more reasonable.

There is still some test code present on the back end. This will be
removed once actuall examples of the new modal are in place.
2024-01-31 23:00:50 -08:00
Sylvia Crowe fa9a0bd228 merge branch 'main' into use-ssh-library--add-user-input 2024-01-31 14:46:43 -08:00
Sylvia Crowe fa2c684c0e fix: add props to user input request modal
There was a second place that the modals were created that I previously
missed. This fixes that second casel
2024-01-31 11:58:32 -08:00
Sylvia Crowe 750e8bc9f7 refactor: update user input backend/interface
This updates the user input backend to fix a few potential bugs. It also
refactors the user input request and response types to better handle
markdown and errors while making it more convenient to work with.

A couple frontend changes were made to keep everything compatible.
2024-01-31 03:43:22 -08:00
Sylvia Crowe f781e358e5 feat: create frontend for user input requests
This is part of a change to allow the backend to request user input from
the frontend. This adds a component specifically for handling this
logic. It is only a starting point, and does not work perfectly yet.
2024-01-30 22:50:40 -08:00
Sylvia Crowe 98f6b84d3e feat: create backend for user input requests
This is the first part of a change that allows the backend to request
user input from the frontend. Essentially, the backend will send a
request for the user to answer some query, and the frontend will send
that answer back. It is blocking, so it needs to be used within a
goroutine.

There is some placeholder code in the frontend that will be updated in
future commits. Similarly, there is some debug code in the backend
remote.go file.
2024-01-29 16:19:34 -08:00
146 changed files with 2538 additions and 2625 deletions
+5 -2
View File
@@ -7,9 +7,10 @@ import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { If } from "tsx-control-statements/components";
import dayjs from "dayjs";
import type { ContextMenuOpts } from "../types/types";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "@/models";
import { isBlank } from "@/util/util";
import { GlobalModel } from "../models";
import { isBlank } from "../util/util";
import { WorkspaceView } from "./workspace/workspaceview";
import { PluginsView } from "./pluginsview/pluginsview";
import { BookmarksView } from "./bookmarks/bookmarks";
@@ -24,6 +25,8 @@ import "./app.less";
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class App extends React.Component<{}, {}> {
dcWait: OV<boolean> = mobx.observable.box(false, { name: "dcWait" });
-10
View File
@@ -47,13 +47,3 @@ export const TabIcons = [
export const VERSION = __WAVETERM_VERSION__;
// @ts-ignore
export const BUILD = __WAVETERM_BUILD__;
/**
* Levels for the screen status indicator
*/
export enum StatusIndicatorLevel {
None = 0,
Output = 1,
Success = 2,
Error = 3,
}
+1 -1
View File
@@ -1,4 +1,4 @@
@import "@/common/themes/themes.less";
@import "../../app/common/themes/themes.less";
.bookmarks-view {
background-color: @background-session;
+8 -7
View File
@@ -7,14 +7,15 @@ import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import { GlobalModel } from "@/models";
import { CmdStrCode, Markdown } from "@/common/elements";
import type { BookmarkType } from "../../types/types";
import { GlobalModel } from "../../models";
import { CmdStrCode, Markdown } from "../common/elements";
import { ReactComponent as XmarkIcon } from "@/assets/icons/line/xmark.svg";
import { ReactComponent as CopyIcon } from "@/assets/icons/favourites/copy.svg";
import { ReactComponent as PenIcon } from "@/assets/icons/favourites/pen.svg";
import { ReactComponent as TrashIcon } from "@/assets/icons/favourites/trash.svg";
import { ReactComponent as FavoritesIcon } from "@/assets/icons/favourites.svg";
import { ReactComponent as XmarkIcon } from "../assets/icons/line/xmark.svg";
import { ReactComponent as CopyIcon } from "../assets/icons/favourites/copy.svg";
import { ReactComponent as PenIcon } from "../assets/icons/favourites/pen.svg";
import { ReactComponent as TrashIcon } from "../assets/icons/favourites/trash.svg";
import { ReactComponent as FavoritesIcon } from "../assets/icons/favourites.svg";
import "./bookmarks.less";
+1 -1
View File
@@ -1,4 +1,4 @@
@import "@/common/themes/themes.less";
@import "../../app/common/themes/themes.less";
.clientsettings-view {
background-color: @background-session;
+23 -55
View File
@@ -6,19 +6,20 @@ import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, RemotesModel } from "@/models";
import { Toggle, InlineSettingsTextEdit, SettingsError, Dropdown } from "@/common/elements";
import { commandRtnHandler, isBlank } from "@/util/util";
import * as appconst from "@/app/appconst";
import { GlobalModel, GlobalCommandRunner, RemotesModel } from "../../models";
import { Toggle, InlineSettingsTextEdit, SettingsError, Dropdown } from "../common/elements";
import * as types from "../../types/types";
import { commandRtnHandler, isBlank } from "../../util/util";
import * as appconst from "../appconst";
import "./clientsettings.less";
@mobxReact.observer
class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> {
fontSizeDropdownActive: OV<boolean> = mobx.observable.box(false, {
fontSizeDropdownActive: types.OV<boolean> = mobx.observable.box(false, {
name: "clientSettings-fontSizeDropdownActive",
});
errorMessage: OV<string> = mobx.observable.box(null, { name: "ClientSettings-errorMessage" });
errorMessage: types.OV<string> = mobx.observable.box(null, { name: "ClientSettings-errorMessage" });
@boundMethod
dismissError(): void {
@@ -29,12 +30,12 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
@boundMethod
handleChangeFontSize(fontSize: string): void {
const newFontSize = Number(fontSize);
let newFontSize = Number(fontSize);
this.fontSizeDropdownActive.set(false);
if (GlobalModel.termFontSize.get() == newFontSize) {
return;
}
const prtn = GlobalCommandRunner.setTermFontSize(newFontSize, false);
let prtn = GlobalCommandRunner.setTermFontSize(newFontSize, false);
commandRtnHandler(prtn, this.errorMessage);
}
@@ -47,7 +48,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
@boundMethod
handleChangeTelemetry(val: boolean): void {
let prtn: Promise<CommandRtnType> = null;
let prtn: Promise<types.CommandRtnType> = null;
if (val) {
prtn = GlobalCommandRunner.telemetryOn(false);
} else {
@@ -58,7 +59,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
@boundMethod
handleChangeReleaseCheck(val: boolean): void {
let prtn: Promise<CommandRtnType> = null;
let prtn: Promise<types.CommandRtnType> = null;
if (val) {
prtn = GlobalCommandRunner.releaseCheckAutoOn(false);
} else {
@@ -67,29 +68,29 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
commandRtnHandler(prtn, this.errorMessage);
}
getFontSizes(): DropdownItem[] {
const availableFontSizes: DropdownItem[] = [];
getFontSizes(): any {
let availableFontSizes: { label: string; value: number }[] = [];
for (let s = appconst.MinFontSize; s <= appconst.MaxFontSize; s++) {
availableFontSizes.push({ label: s + "px", value: String(s) });
availableFontSizes.push({ label: s + "px", value: s });
}
return availableFontSizes;
}
@boundMethod
inlineUpdateOpenAIModel(newModel: string): void {
const prtn = GlobalCommandRunner.setClientOpenAISettings({ model: newModel });
let prtn = GlobalCommandRunner.setClientOpenAISettings({ model: newModel });
commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
inlineUpdateOpenAIToken(newToken: string): void {
const prtn = GlobalCommandRunner.setClientOpenAISettings({ apitoken: newToken });
let prtn = GlobalCommandRunner.setClientOpenAISettings({ apitoken: newToken });
commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
inlineUpdateOpenAIMaxTokens(newMaxTokensStr: string): void {
const prtn = GlobalCommandRunner.setClientOpenAISettings({ maxtokens: newMaxTokensStr });
let prtn = GlobalCommandRunner.setClientOpenAISettings({ maxtokens: newMaxTokensStr });
commandRtnHandler(prtn, this.errorMessage);
}
@@ -105,41 +106,19 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
GlobalModel.clientSettingsViewModel.closeView();
}
@boundMethod
handleChangeShortcut(newShortcut: string): void {
const prtn = GlobalCommandRunner.setGlobalShortcut(newShortcut);
commandRtnHandler(prtn, this.errorMessage);
}
getFKeys(): DropdownItem[] {
const opts: DropdownItem[] = [];
opts.push({ label: "Disabled", value: "" });
const platform = GlobalModel.getPlatform();
for (let i = 1; i <= 12; i++) {
const shortcut = (platform == "darwin" ? "Cmd" : "Alt") + "+F" + String(i);
opts.push({ label: shortcut, value: shortcut });
}
return opts;
}
getCurrentShortcut(): string {
const clientData = GlobalModel.clientData.get();
return clientData?.clientopts?.globalshortcut ?? "";
}
render() {
const isHidden = GlobalModel.activeMainView.get() != "clientsettings";
let isHidden = GlobalModel.activeMainView.get() != "clientsettings";
if (isHidden) {
return null;
}
const cdata: ClientDataType = GlobalModel.clientData.get();
const openAIOpts = cdata.openaiopts ?? {};
const apiTokenStr = isBlank(openAIOpts.apitoken) ? "(not set)" : "********";
const maxTokensStr = String(
let cdata: types.ClientDataType = GlobalModel.clientData.get();
let openAIOpts = cdata.openaiopts ?? {};
let apiTokenStr = isBlank(openAIOpts.apitoken) ? "(not set)" : "********";
let maxTokensStr = String(
openAIOpts.maxtokens == null || openAIOpts.maxtokens == 0 ? 1000 : openAIOpts.maxtokens
);
const curFontSize = GlobalModel.termFontSize.get();
let curFontSize = GlobalModel.termFontSize.get();
return (
<div className={cn("view clientsettings-view")}>
@@ -229,17 +208,6 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
/>
</div>
</div>
<div className="settings-field">
<div className="settings-label">Global Hotkey</div>
<div className="settings-input">
<Dropdown
className="hotkey-dropdown"
options={this.getFKeys()}
defaultValue={this.getCurrentShortcut()}
onChange={this.handleChangeShortcut}
/>
</div>
</div>
<SettingsError errorMessage={this.errorMessage} />
</div>
</div>
+1 -1
View File
@@ -1,4 +1,4 @@
@import "@/common/themes/themes.less";
@import "../../../app/common/themes/themes.less";
.wave-button {
background: none;
+1 -1
View File
@@ -1,4 +1,4 @@
@import "@/common/themes/themes.less";
@import "../../../app/common/themes/themes.less";
.checkbox {
display: flex;
+1 -1
View File
@@ -1,4 +1,4 @@
@import "@/common/themes/themes.less";
@import "../../../app/common/themes/themes.less";
.cmdstr-code {
position: relative;
+2 -2
View File
@@ -6,8 +6,8 @@ import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { If } from "tsx-control-statements/components";
import { ReactComponent as CheckIcon } from "@/assets/icons/line/check.svg";
import { ReactComponent as CopyIcon } from "@/assets/icons/history/copy.svg";
import { ReactComponent as CheckIcon } from "../../assets/icons/line/check.svg";
import { ReactComponent as CopyIcon } from "../../assets/icons/history/copy.svg";
import "./cmdstrcode.less";
+1 -1
View File
@@ -1,4 +1,4 @@
@import "@/common/themes/themes.less";
@import "../../../app/common/themes/themes.less";
.wave-dropdown {
position: relative;
+1 -1
View File
@@ -17,7 +17,7 @@ interface DropdownDecorationProps {
interface DropdownProps {
label?: string;
options: DropdownItem[];
options: { value: string; label: string }[];
value?: string;
className?: string;
onChange: (value: string) => void;
@@ -1,4 +1,4 @@
@import "@/common/themes/themes.less";
@import "../../../app/common/themes/themes.less";
.inline-edit {
.icon {
@@ -7,10 +7,12 @@ import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { If } from "tsx-control-statements/components";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "../../../util/keyutil";
import "./inlinesettingstextedit.less";
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class InlineSettingsTextEdit extends React.Component<
{
+1 -1
View File
@@ -1,4 +1,4 @@
@import "@/common/themes/themes.less";
@import "../../../app/common/themes/themes.less";
.wave-input-decoration {
display: flex;
+1 -1
View File
@@ -1,4 +1,4 @@
@import "@/common/themes/themes.less";
@import "../../../app/common/themes/themes.less";
.markdown {
color: @term-white;
+1 -1
View File
@@ -6,7 +6,7 @@ import * as mobxReact from "mobx-react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import cn from "classnames";
import { GlobalModel } from "@/models";
import { GlobalModel } from "../../../models";
import "./markdown.less";
+1 -1
View File
@@ -1,4 +1,4 @@
@import "@/common/themes/themes.less";
@import "../../../app/common/themes/themes.less";
.wave-modal-container {
position: fixed;
+2
View File
@@ -10,6 +10,8 @@ import { IconButton } from "./iconbutton";
import "./modal.less";
type OV<V> = mobx.IObservableValue<V>;
interface ModalHeaderProps {
onClose?: () => void;
title: string;
+1 -1
View File
@@ -1,4 +1,4 @@
@import "@/common/themes/themes.less";
@import "../../../app/common/themes/themes.less";
.wave-password {
.wave-textfield-inner-eye {

Some files were not shown because too many files have changed in this diff Show More