Merge branch 'release-1.0'
@@ -1,7 +0,0 @@
|
||||
# ~/.bash_logout: executed by bash(1) when login shell exits.
|
||||
|
||||
# when leaving the console clear the screen to increase privacy
|
||||
|
||||
if [ "$SHLVL" = 1 ]; then
|
||||
[ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q
|
||||
fi
|
||||
@@ -1 +0,0 @@
|
||||
{"Key":"unix:///var/run/docker.sock","Name":"","Global":false}
|
||||
48
.github/workflows/docker-image.yml
vendored
@@ -1,4 +1,5 @@
|
||||
name: Build and Push Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@@ -8,7 +9,7 @@ on:
|
||||
tag_name:
|
||||
description: "Custom tag name for the Docker image"
|
||||
required: false
|
||||
default: "development-latest"
|
||||
default: ""
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -16,49 +17,64 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
|
||||
- name: Install Dependencies and Build Frontend
|
||||
run: |
|
||||
cd frontend
|
||||
npm install
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
|
||||
- name: Login to Docker Registry
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
- name: Determine Docker image tag
|
||||
run: |
|
||||
echo "REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
|
||||
if [ -n "${{ github.event.inputs.tag_name }}" ]; then
|
||||
IMAGE_TAG="${{ github.event.inputs.tag_name }}"
|
||||
if [ "${{ github.event.inputs.tag_name }}" == "" ]; then
|
||||
IMAGE_TAG="${{ github.ref_name }}-development-latest"
|
||||
else
|
||||
IMAGE_TAG="development-latest"
|
||||
IMAGE_TAG="${{ github.event.inputs.tag_name }}"
|
||||
fi
|
||||
echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV
|
||||
|
||||
|
||||
- name: Build and Push Docker Image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
push: true
|
||||
tags: ghcr.io/${{ env.REPO_OWNER }}/ssh-project:${{ env.IMAGE_TAG }}
|
||||
tags: ghcr.io/${{ env.REPO_OWNER }}/termix:${{ env.IMAGE_TAG }}
|
||||
labels: org.opencontainers.image.source=https://github.com/${{ github.repository }}
|
||||
|
||||
- name: Cleanup Docker Images
|
||||
run: docker image prune -af
|
||||
|
||||
- name: Notify via ntfy
|
||||
run: |
|
||||
curl -d "Docker image build and push completed successfully for tag: ${{ env.IMAGE_TAG }}" \
|
||||
https://ntfy.karmaashomepage.online/termix-build
|
||||
|
||||
- name: Delete all untagged image versions
|
||||
uses: quartx-analytics/ghcr-cleaner@v1
|
||||
with:
|
||||
owner-type: user
|
||||
token: ${{ secrets.GHCR_TOKEN }}
|
||||
repository-owner: ${{ github.repository_owner }}
|
||||
delete-untagged: true
|
||||
|
||||
- name: Cleanup Docker Images Locally
|
||||
run: |
|
||||
docker image prune -af
|
||||
docker system prune -af --volumes
|
||||
2
.gitignore
vendored
@@ -133,6 +133,8 @@ yarn-error.log*
|
||||
.sudo_as_admin_successful
|
||||
.wget-hsts
|
||||
.git-credentials
|
||||
.docker/
|
||||
.bash_logout
|
||||
|
||||
# VSCode Files
|
||||
.vscode-server/
|
||||
|
||||
1
.idea/.name
generated
Normal file
@@ -0,0 +1 @@
|
||||
Termix
|
||||
12
.idea/Termix.iml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
1
.idea/icon.svg
generated
Normal file
|
After Width: | Height: | Size: 47 KiB |
2
.idea/modules.xml
generated
@@ -2,7 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/SSH-Project-JB.iml" filepath="$PROJECT_DIR$/.idea/SSH-Project-JB.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Termix.iml" filepath="$PROJECT_DIR$/.idea/Termix.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/vcs.xml
generated
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
467
.idea/workspace.xml
generated
Normal file
@@ -0,0 +1,467 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="8497df64-d86b-4c98-ac58-c157d9d3fb1e" name="Changes" comment="Fix timeout on close.">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/frontend/src/App.jsx" beforeDir="false" afterPath="$PROJECT_DIR$/frontend/src/App.jsx" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||
<map>
|
||||
<entry key="$PROJECT_DIR$" value="release-1.0" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="GitHubPullRequestSearchHistory">{
|
||||
"lastFilter": {}
|
||||
}</component>
|
||||
<component name="GithubPullRequestsUISettings">{
|
||||
"selectedUrlAndAccountId": {
|
||||
"url": "https://github.com/LukeGus/Termix",
|
||||
"accountId": "f107d505-1915-4c73-a3f4-e0440737e1dc"
|
||||
}
|
||||
}</component>
|
||||
<component name="ProjectColorInfo">{
|
||||
"customColor": "636378de",
|
||||
"associatedIndex": 8
|
||||
}</component>
|
||||
<component name="ProjectId" id="2pojjnjB8kTL4lo1P2No1yvZp4c" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
|
||||
<ConfirmationsSetting value="1" id="Add" />
|
||||
</component>
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"Shell Script.Node Server.js Start.executor": "Run",
|
||||
"Shell Script.Run backend and frontend.executor": "Run",
|
||||
"Shell Script.run_backend_frontend.executor": "Run",
|
||||
"git-widget-placeholder": "release-1.0",
|
||||
"ignore.virus.scanning.warn.message": "true",
|
||||
"last_opened_file_path": "C:/Users/Luke/Documents/Personal Projects/Termix/frontend",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"npm.run_start.executor": "Run",
|
||||
"npm.run_start_frontend.executor": "Run",
|
||||
"npm.run_start_node_backend.executor": "Run",
|
||||
"npm.run_start_vite.executor": "Run",
|
||||
"npm.start.executor": "Run",
|
||||
"settings.editor.selected.configurable": "ml.llm.LLMConfigurable",
|
||||
"ts.external.directory.path": "D:\\Program Files (x86)\\Applications\\Jetbrains Webstorm\\WebStorm 2024.3.1\\plugins\\javascript-plugin\\jsLanguageServicesImpl\\external",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="C:\Users\Luke\Documents\Personal Projects\Termix\frontend" />
|
||||
<recent name="C:\Users\Luke\Documents\Personal Projects\Termix" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="C:\Users\Luke\Documents\Personal Projects\Termix\frontend\src" />
|
||||
<recent name="D:\Programming Projects\Termix\repo-images" />
|
||||
<recent name="D:\Programming Projects\SSH-Project-JB\public" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="Shell Script.run_backend_frontend">
|
||||
<configuration name="run_backend_frontend" type="ShConfigurationType">
|
||||
<option name="SCRIPT_TEXT" value="Start-Process "powershell" -ArgumentList "-NoProfile", "-Command npm run start-vite"; Start-Process "powershell" -ArgumentList "-NoProfile", "-Command npm run start-server" " />
|
||||
<option name="INDEPENDENT_SCRIPT_PATH" value="false" />
|
||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/../../../../../Windows/System32/WindowsPowerShell/v1.0/powershell.exe" />
|
||||
<option name="SCRIPT_OPTIONS" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="false" />
|
||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/frontend" />
|
||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="false" />
|
||||
<option name="INTERPRETER_PATH" value="$PROJECT_DIR$/../../../../../Windows/System32/WindowsPowerShell/v1.0/powershell.exe" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||
<option name="EXECUTE_SCRIPT_FILE" value="false" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="run_start_frontend" type="js.build_tools.npm">
|
||||
<package-json value="$PROJECT_DIR$/frontend/package.json" />
|
||||
<command value="start" />
|
||||
<node-interpreter value="project" />
|
||||
<envs />
|
||||
<EXTENSION ID="com.intellij.lang.javascript.buildTools.npm.rc.StartBrowserRunConfigurationExtension">
|
||||
<browser name="a7bb68e0-33c0-4d6f-a81a-aac1fdb870c8" start="true" url="http://localhost:8080" />
|
||||
</EXTENSION>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<list>
|
||||
<item itemvalue="Shell Script.run_backend_frontend" />
|
||||
<item itemvalue="npm.run_start_frontend" />
|
||||
</list>
|
||||
</component>
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-js-predefined-d6986cc7102b-deb605915726-JavaScript-WS-243.22562.112" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="8497df64-d86b-4c98-ac58-c157d9d3fb1e" name="Changes" comment="" />
|
||||
<created>1733439468142</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1733439468142</updated>
|
||||
<workItem from="1733439479708" duration="5489000" />
|
||||
<workItem from="1733448523969" duration="3535000" />
|
||||
<workItem from="1733549186397" duration="8748000" />
|
||||
<workItem from="1733599078854" duration="1895000" />
|
||||
<workItem from="1733601633451" duration="10190000" />
|
||||
<workItem from="1733644355292" duration="59000" />
|
||||
<workItem from="1733644430242" duration="42000" />
|
||||
<workItem from="1733688686708" duration="3433000" />
|
||||
<workItem from="1733804654516" duration="339000" />
|
||||
<workItem from="1733805003742" duration="9000" />
|
||||
<workItem from="1733883751079" duration="757000" />
|
||||
<workItem from="1733884522510" duration="3958000" />
|
||||
<workItem from="1734052874393" duration="34000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="Nano zoom fix #11">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733447944692</created>
|
||||
<option name="number" value="00001" />
|
||||
<option name="presentableId" value="LOCAL-00001" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733447944692</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00002" summary="Nano zoom fix #11">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733448864234</created>
|
||||
<option name="number" value="00002" />
|
||||
<option name="presentableId" value="LOCAL-00002" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733448864234</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00003" summary="Nano zoom fix #11">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733449234908</created>
|
||||
<option name="number" value="00003" />
|
||||
<option name="presentableId" value="LOCAL-00003" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733449234908</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00004" summary="Nano zoom fix #12">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733449331913</created>
|
||||
<option name="number" value="00004" />
|
||||
<option name="presentableId" value="LOCAL-00004" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733449331913</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00005" summary="Nano zoom fix #13">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733449760767</created>
|
||||
<option name="number" value="00005" />
|
||||
<option name="presentableId" value="LOCAL-00005" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733449760767</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00006" summary="Nano zoom fix #14">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733450304640</created>
|
||||
<option name="number" value="00006" />
|
||||
<option name="presentableId" value="LOCAL-00006" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733450304640</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00007" summary="Nano zoom fix #15">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733450681262</created>
|
||||
<option name="number" value="00007" />
|
||||
<option name="presentableId" value="LOCAL-00007" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733450681262</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00008" summary="Nano zoom fix #16 (ssh-2-promise)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733451925922</created>
|
||||
<option name="number" value="00008" />
|
||||
<option name="presentableId" value="LOCAL-00008" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733451925922</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00009" summary="Full return back to old code with minor fixes">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733532896448</created>
|
||||
<option name="number" value="00009" />
|
||||
<option name="presentableId" value="LOCAL-00009" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733532896448</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00010" summary="Terminal size fix #18 (rows & cols fix)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733538097802</created>
|
||||
<option name="number" value="00010" />
|
||||
<option name="presentableId" value="LOCAL-00010" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733538097802</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00011" summary="Test ntfy build notification system">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733539381433</created>
|
||||
<option name="number" value="00011" />
|
||||
<option name="presentableId" value="LOCAL-00011" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733539381433</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00012" summary="Silent resize cmds & Auto resize terminal #1">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733553128900</created>
|
||||
<option name="number" value="00012" />
|
||||
<option name="presentableId" value="LOCAL-00012" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733553128900</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00013" summary="Silent resize cmds & Auto resize terminal #2">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733553902375</created>
|
||||
<option name="number" value="00013" />
|
||||
<option name="presentableId" value="LOCAL-00013" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733553902375</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00014" summary="Docker build update">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733555933987</created>
|
||||
<option name="number" value="00014" />
|
||||
<option name="presentableId" value="LOCAL-00014" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733555933987</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00015" summary="Docker build update #2">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733556269270</created>
|
||||
<option name="number" value="00015" />
|
||||
<option name="presentableId" value="LOCAL-00015" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733556269270</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00016" summary="Docker build update #3">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733556428424</created>
|
||||
<option name="number" value="00016" />
|
||||
<option name="presentableId" value="LOCAL-00016" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733556428424</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00017" summary="Docker build update #4 (cache and cleanup)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733556699034</created>
|
||||
<option name="number" value="00017" />
|
||||
<option name="presentableId" value="LOCAL-00017" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733556699034</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00018" summary="Docker build update #5 (cache and cleanup)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733556917800</created>
|
||||
<option name="number" value="00018" />
|
||||
<option name="presentableId" value="LOCAL-00018" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733556917800</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00019" summary="Docker build update #5 (cache and cleanup)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733557286584</created>
|
||||
<option name="number" value="00019" />
|
||||
<option name="presentableId" value="LOCAL-00019" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733557286584</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00020" summary="Docker build update #6 (cache and cleanup)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733557337662</created>
|
||||
<option name="number" value="00020" />
|
||||
<option name="presentableId" value="LOCAL-00020" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733557337662</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00021" summary="Docker build update #7 (final)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733557558085</created>
|
||||
<option name="number" value="00021" />
|
||||
<option name="presentableId" value="LOCAL-00021" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733557558085</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00022" summary="Docker build update #8 (nevermind not finanl)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733557773727</created>
|
||||
<option name="number" value="00022" />
|
||||
<option name="presentableId" value="LOCAL-00022" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733557773727</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00023" summary="Docker build update #9 (nevermind not finanl)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733558138278</created>
|
||||
<option name="number" value="00023" />
|
||||
<option name="presentableId" value="LOCAL-00023" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733558138278</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00024" summary="Docker build update #10">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733558347319</created>
|
||||
<option name="number" value="00024" />
|
||||
<option name="presentableId" value="LOCAL-00024" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733558347319</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00025" summary="Docker build update #10 (I hope final)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733558781194</created>
|
||||
<option name="number" value="00025" />
|
||||
<option name="presentableId" value="LOCAL-00025" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733558781194</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00026" summary="Docker build update #10 (actual final)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733558952696</created>
|
||||
<option name="number" value="00026" />
|
||||
<option name="presentableId" value="LOCAL-00026" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733558952696</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00027" summary="Release 1.0!!!!">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733603759658</created>
|
||||
<option name="number" value="00027" />
|
||||
<option name="presentableId" value="LOCAL-00027" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733603759658</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00028" summary="Update README.md #4">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733688870582</created>
|
||||
<option name="number" value="00028" />
|
||||
<option name="presentableId" value="LOCAL-00028" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733688870582</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00029" summary="Add images">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733691729582</created>
|
||||
<option name="number" value="00029" />
|
||||
<option name="presentableId" value="LOCAL-00029" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733691729582</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00030" summary="Update image name">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733691982293</created>
|
||||
<option name="number" value="00030" />
|
||||
<option name="presentableId" value="LOCAL-00030" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733691982293</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00031" summary="Final changes to release-1.0">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733692181011</created>
|
||||
<option name="number" value="00031" />
|
||||
<option name="presentableId" value="LOCAL-00031" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733692181011</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00032" summary="Update name (need to fix logo)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733692962039</created>
|
||||
<option name="number" value="00032" />
|
||||
<option name="presentableId" value="LOCAL-00032" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733692962039</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00033" summary="Final updates (I hope for real this time)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733886236040</created>
|
||||
<option name="number" value="00033" />
|
||||
<option name="presentableId" value="LOCAL-00033" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733886236040</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00034" summary="Fix web-socket timeout.">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733887722496</created>
|
||||
<option name="number" value="00034" />
|
||||
<option name="presentableId" value="LOCAL-00034" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733887722496</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00035" summary="Fix timeout on close.">
|
||||
<option name="closed" value="true" />
|
||||
<created>1733887980750</created>
|
||||
<option name="number" value="00035" />
|
||||
<option name="presentableId" value="LOCAL-00035" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1733887980750</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="36" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State />
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="Terminal size fix #18 (rows & cols fix)" />
|
||||
<MESSAGE value="Test ntfy build notification system" />
|
||||
<MESSAGE value="Silent resize cmds & Auto resize terminal #1" />
|
||||
<MESSAGE value="Silent resize cmds & Auto resize terminal #2" />
|
||||
<MESSAGE value="Docker build update" />
|
||||
<MESSAGE value="Docker build update #2" />
|
||||
<MESSAGE value="Docker build update #3" />
|
||||
<MESSAGE value="Docker build update #4 (cache and cleanup)" />
|
||||
<MESSAGE value="Docker build update #5 (cache and cleanup)" />
|
||||
<MESSAGE value="Docker build update #6 (cache and cleanup)" />
|
||||
<MESSAGE value="Docker build update #7 (final)" />
|
||||
<MESSAGE value="Docker build update #8 (nevermind not finanl)" />
|
||||
<MESSAGE value="Docker build update #9 (nevermind not finanl)" />
|
||||
<MESSAGE value="Docker build update #10" />
|
||||
<MESSAGE value="Docker build update #10 (I hope final)" />
|
||||
<MESSAGE value="Docker build update #10 (actual final)" />
|
||||
<MESSAGE value="Release 1.0!!!!" />
|
||||
<MESSAGE value="Update README.md #4" />
|
||||
<MESSAGE value="Add images" />
|
||||
<MESSAGE value="Update image name" />
|
||||
<MESSAGE value="Final changes to release-1.0" />
|
||||
<MESSAGE value="Update name (need to fix logo)" />
|
||||
<MESSAGE value="Final updates (I hope for real this time)" />
|
||||
<MESSAGE value="Fix web-socket timeout." />
|
||||
<MESSAGE value="Fix timeout on close." />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Fix timeout on close." />
|
||||
</component>
|
||||
</project>
|
||||
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Luke Gustafson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
50
README.md
@@ -1 +1,49 @@
|
||||
SSH is silly
|
||||
# Repo Stats
|
||||

|
||||

|
||||

|
||||
#### Top Technologies
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
|
||||
<br />
|
||||
<p align="center">
|
||||
<a href="https://github.com/LukeGus/Termix">
|
||||
<img alt="Termimx Banner" src=./repo-images/TermixLogo.png style="width: 125px; height: auto;"> </a>
|
||||
</p>
|
||||
|
||||
# Description
|
||||
Termix is an open-source forever free self-hosted SSH (other protocols planned, see [Planned Features](#planned-features)) management panel inspired by [Nexterm](https://github.com/gnmyt/Nexterm). Its purpose is to provide an all-in-one docker-hosted web solution to manage your servers in one easy place. I'm using this project to help me learn [React](https://github.com/facebook/react), [Vite](https://github.com/vitejs/vite-plugin-react), and [Docker](https://www.docker.com) but also because I could never settle on a server management software that I enjoyed to use.
|
||||
|
||||
> [!WARNING]
|
||||
> This app is in the VERY early stages of development. Expect bugs, data loss, and possibly even security issues!
|
||||
|
||||
# Planned Features
|
||||
- [x] SSH
|
||||
- [ ] VNC
|
||||
- [ ] RDP
|
||||
- [ ] SMTP (build in file transfer)
|
||||
- [ ] Split Screen & Tabs
|
||||
- [ ] ChatGPT/Ollama Integration (for commands)
|
||||
- [ ] Login Screen
|
||||
|
||||
# How Termix is Different
|
||||
Before developing Termix, I faced the issue of a server management panel that did not have every feature I liked. [Guacamole](https://guacamole.apache.org/) had poor copy/paste abilities and a poor UI. [Shellngn](https://shellngn.com/) was too expensive and all other alternatives had one major problem with them. I plan to develop the management panel of my dreams with even an AI integration for those pesky commands I always forget the syntax of.
|
||||
|
||||
# Installation
|
||||
View the Termix [Wiki](https://github.com/LukeGus/Termix/wiki) for information on how to install Termix. You can also use these links to go directly to guide. [Docker](https://github.com/LukeGus/Termix/wiki/Docker) or [Manual](https://github.com/LukeGus/Termix/wiki/Manual).
|
||||
|
||||
# Known Bugs
|
||||
### Please create an [Issue](https://github.com/LukeGus/Termix/issues) if you find any problems!
|
||||
Start session button stays connected even if SSH fails to connect.
|
||||
|
||||
# Show-off
|
||||
|
||||

|
||||
|
||||
# License
|
||||
Distributed under the MIT license. See LICENSE for more information.
|
||||
|
||||
73
backend/package-lock.json
generated
@@ -11,6 +11,8 @@
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"express": "^4.21.1",
|
||||
"guacamole-common-js": "^1.5.0",
|
||||
"http-proxy-middleware": "^3.0.3",
|
||||
@@ -1501,6 +1503,19 @@
|
||||
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@xterm/addon-fit": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz",
|
||||
"integrity": "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==",
|
||||
"peerDependencies": {
|
||||
"@xterm/xterm": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@xterm/xterm": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A=="
|
||||
},
|
||||
"node_modules/abab": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
||||
@@ -2288,10 +2303,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
|
||||
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
|
||||
"license": "MIT",
|
||||
"version": "4.21.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
@@ -2312,7 +2326,7 @@
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.10",
|
||||
"path-to-regexp": "0.1.12",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
@@ -2327,6 +2341,10 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/debug": {
|
||||
@@ -3394,9 +3412,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
||||
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -3404,6 +3422,7 @@
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
@@ -3539,10 +3558,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
|
||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
|
||||
"license": "MIT"
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
|
||||
},
|
||||
"node_modules/pathe": {
|
||||
"version": "1.1.1",
|
||||
@@ -5774,6 +5792,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@xterm/addon-fit": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz",
|
||||
"integrity": "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"@xterm/xterm": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A=="
|
||||
},
|
||||
"abab": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
||||
@@ -6320,9 +6349,9 @@
|
||||
}
|
||||
},
|
||||
"express": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
|
||||
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
|
||||
"version": "4.21.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||
"requires": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
@@ -6343,7 +6372,7 @@
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.10",
|
||||
"path-to-regexp": "0.1.12",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
@@ -7096,9 +7125,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"nanoid": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
||||
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
|
||||
"dev": true
|
||||
},
|
||||
"negotiator": {
|
||||
@@ -7185,9 +7214,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
|
||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
|
||||
},
|
||||
"pathe": {
|
||||
"version": "1.1.1",
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"express": "^4.21.1",
|
||||
"guacamole-common-js": "^1.5.0",
|
||||
"http-proxy-middleware": "^3.0.3",
|
||||
@@ -55,4 +57,4 @@
|
||||
"vite": "^4.5.5",
|
||||
"vitest": "^0.34.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,97 +2,104 @@ const WebSocket = require('ws');
|
||||
const ssh2 = require('ssh2');
|
||||
const http = require('http');
|
||||
|
||||
// Create an HTTP server to serve WebSocket connections
|
||||
const server = http.createServer((req, res) => {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
res.end('WebSocket server is running\n');
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
res.end('WebSocket server is running\n');
|
||||
});
|
||||
|
||||
// Create a WebSocket server attached to the HTTP server
|
||||
const wss = new WebSocket.Server({ server });
|
||||
|
||||
// WebSocket connection handling
|
||||
wss.on('connection', (ws) => {
|
||||
console.log('WebSocket connection established');
|
||||
console.log('WebSocket connection established');
|
||||
|
||||
let conn = null; // Declare SSH client outside to manage lifecycle
|
||||
let conn = new ssh2.Client();
|
||||
let stream = null;
|
||||
let currentCols = 80;
|
||||
let currentRows = 24;
|
||||
let interval = null;
|
||||
|
||||
ws.on('message', (message) => {
|
||||
try {
|
||||
const data = JSON.parse(message); // Try parsing the incoming message as JSON
|
||||
|
||||
// Check if message contains SSH connection details
|
||||
if (data.host && data.username && data.password) {
|
||||
if (conn) {
|
||||
conn.end(); // Close any previous connection before starting a new one
|
||||
const resizeTerminal = (cols, rows) => {
|
||||
if (stream && stream.setWindow) {
|
||||
stream.setWindow(rows, cols, rows * 100, cols * 100); // Adjust terminal size
|
||||
console.log(`Terminal resized successfully: cols=${cols}, rows=${rows}`);
|
||||
}
|
||||
};
|
||||
|
||||
conn = new ssh2.Client(); // Create a new SSH connection instance
|
||||
ws.on('message', (message) => {
|
||||
const messageStr = message.toString();
|
||||
|
||||
// When the SSH connection is ready
|
||||
conn.on('ready', () => {
|
||||
console.log('SSH Connection established');
|
||||
|
||||
// Start an interactive shell session
|
||||
conn.shell((err, stream) => {
|
||||
if (err) {
|
||||
console.log(`SSH Error: ${err}`);
|
||||
ws.send(`Error: ${err}`);
|
||||
return;
|
||||
let data;
|
||||
try {
|
||||
if (messageStr.trim().startsWith('{')) {
|
||||
data = JSON.parse(messageStr);
|
||||
} else if (stream && stream.writable) {
|
||||
stream.write(messageStr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle data from SSH session
|
||||
stream.on('data', (data) => {
|
||||
console.log(`SSH Output: ${data}`);
|
||||
ws.send(data.toString()); // Send the SSH output back to WebSocket client
|
||||
});
|
||||
|
||||
// Handle stream close event
|
||||
stream.on('close', () => {
|
||||
console.log('SSH stream closed');
|
||||
conn.end();
|
||||
});
|
||||
|
||||
// When the WebSocket client sends a message (from terminal input), forward it to the SSH stream
|
||||
ws.on('message', (message) => {
|
||||
console.log(`Received message from WebSocket: ${message}`);
|
||||
stream.write(message); // Write the message (input) to the SSH shell
|
||||
});
|
||||
});
|
||||
}).on('error', (err) => {
|
||||
console.log('SSH Connection Error: ', err);
|
||||
ws.send(`SSH Error: ${err}`);
|
||||
}).connect({
|
||||
host: data.host, // Host provided from the client
|
||||
port: 22, // Default SSH port
|
||||
username: data.username, // Username provided from the client
|
||||
password: data.password, // Password provided from the client
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
// If message is not valid JSON (i.e., terminal input), treat it as raw text and send it to SSH
|
||||
console.log('Received non-JSON message, sending to SSH session:', message);
|
||||
if (conn) {
|
||||
const stream = conn._stream; // Access the SSH stream directly
|
||||
if (stream && stream.writable) {
|
||||
stream.write(message); // Write raw input message to SSH stream
|
||||
} catch (error) {
|
||||
console.error('Failed to process message:', error);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
console.error('SSH connection is not established yet.');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle WebSocket close event
|
||||
ws.on('close', () => {
|
||||
console.log('WebSocket closed');
|
||||
if (conn) {
|
||||
conn.end(); // Close SSH connection when WebSocket client disconnects
|
||||
}
|
||||
});
|
||||
if (data?.host && data.port && data.username && data.password) {
|
||||
conn.on('ready', () => {
|
||||
console.log('SSH Connection established');
|
||||
|
||||
interval = setInterval(() => {
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.ping();
|
||||
} else {
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, 15000);
|
||||
|
||||
conn.shell({ term: 'xterm', cols: currentCols, rows: currentRows }, (error, newStream) => {
|
||||
if (error) {
|
||||
console.error(`SSH Shell Error: ${error}`);
|
||||
ws.send(`Error: Could not establish a shell: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
stream = newStream;
|
||||
|
||||
stream.on('data', (chunk) => {
|
||||
ws.send(chunk.toString());
|
||||
});
|
||||
|
||||
stream.on('close', () => {
|
||||
console.log('SSH stream closed');
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).on('error', (err) => {
|
||||
console.log('SSH Connection Error:', err);
|
||||
ws.send(`SSH Connection Error: ${err.message}`);
|
||||
}).connect({
|
||||
host: data.host,
|
||||
port: data.port,
|
||||
username: data.username,
|
||||
password: data.password,
|
||||
keepaliveInterval: 10000,
|
||||
keepaliveCountMax: 5,
|
||||
});
|
||||
} else if (data?.cols && data.rows) {
|
||||
currentCols = data.cols;
|
||||
currentRows = data.rows;
|
||||
resizeTerminal(currentCols, currentRows);
|
||||
}
|
||||
});
|
||||
|
||||
ws.on('close', () => {
|
||||
console.log('WebSocket closed');
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
if (conn) {
|
||||
conn.end();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Start the WebSocket server on port 8081
|
||||
server.listen(8081, () => {
|
||||
console.log('WebSocket server is listening on ws://localhost:8081');
|
||||
console.log('WebSocket server is listening on ws://localhost:8081');
|
||||
});
|
||||
BIN
frontend/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
@@ -2,12 +2,12 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="icon" href="/favicon.ico?v=2" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using @vitejs/plugin-react"
|
||||
content="Sever management software for SSH!"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="/logo192.png" />
|
||||
<!--
|
||||
@@ -15,7 +15,7 @@
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<title>React App</title>
|
||||
<title>Termix</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
73
frontend/package-lock.json
generated
@@ -11,6 +11,8 @@
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"express": "^4.21.1",
|
||||
"guacamole-common-js": "^1.5.0",
|
||||
"http-proxy-middleware": "^3.0.3",
|
||||
@@ -1501,6 +1503,19 @@
|
||||
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@xterm/addon-fit": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz",
|
||||
"integrity": "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==",
|
||||
"peerDependencies": {
|
||||
"@xterm/xterm": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@xterm/xterm": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A=="
|
||||
},
|
||||
"node_modules/abab": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
||||
@@ -2288,10 +2303,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
|
||||
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
|
||||
"license": "MIT",
|
||||
"version": "4.21.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
@@ -2312,7 +2326,7 @@
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.10",
|
||||
"path-to-regexp": "0.1.12",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
@@ -2327,6 +2341,10 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/debug": {
|
||||
@@ -3394,9 +3412,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
||||
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -3404,6 +3422,7 @@
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
@@ -3539,10 +3558,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
|
||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
|
||||
"license": "MIT"
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
|
||||
},
|
||||
"node_modules/pathe": {
|
||||
"version": "1.1.1",
|
||||
@@ -5773,6 +5791,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@xterm/addon-fit": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz",
|
||||
"integrity": "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"@xterm/xterm": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A=="
|
||||
},
|
||||
"abab": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
||||
@@ -6319,9 +6348,9 @@
|
||||
}
|
||||
},
|
||||
"express": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
|
||||
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
|
||||
"version": "4.21.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||
"requires": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
@@ -6342,7 +6371,7 @@
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.10",
|
||||
"path-to-regexp": "0.1.12",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
@@ -7095,9 +7124,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"nanoid": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
||||
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
|
||||
"dev": true
|
||||
},
|
||||
"negotiator": {
|
||||
@@ -7184,9 +7213,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
|
||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
|
||||
},
|
||||
"pathe": {
|
||||
"version": "1.1.1",
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"express": "^4.21.1",
|
||||
"guacamole-common-js": "^1.5.0",
|
||||
"http-proxy-middleware": "^3.0.3",
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -63,7 +62,7 @@
|
||||
.hide-sidebar-button {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
right: 25px;
|
||||
right: 23px;
|
||||
background-color: rgb(108, 108, 108);
|
||||
color: white;
|
||||
border: none;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Terminal } from 'xterm';
|
||||
import { Terminal } from '@xterm/xterm';
|
||||
import 'xterm/css/xterm.css';
|
||||
import { FitAddon } from 'xterm-addon-fit';
|
||||
import { FitAddon } from '@xterm/addon-fit';
|
||||
import './App.css';
|
||||
|
||||
const App = () => {
|
||||
@@ -10,98 +10,109 @@ const App = () => {
|
||||
const fitAddon = useRef(null);
|
||||
const socket = useRef(null);
|
||||
const [host, setHost] = useState('');
|
||||
const [port, setPort] = useState('22');
|
||||
const [username, setUsername] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const [isSideBarHidden, setIsSideBarHidden] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('Initializing terminal...');
|
||||
terminal.current = new Terminal({
|
||||
cursorBlink: true,
|
||||
theme: { background: '#1e1e1e', foreground: '#ffffff' },
|
||||
theme: {
|
||||
background: '#1e1e1e',
|
||||
foreground: '#ffffff',
|
||||
},
|
||||
macOptionIsMeta: true,
|
||||
allowProposedApi: true,
|
||||
fontSize: 14,
|
||||
scrollback: 5000,
|
||||
});
|
||||
|
||||
fitAddon.current = new FitAddon();
|
||||
terminal.current.loadAddon(fitAddon.current);
|
||||
|
||||
if (terminalRef.current) {
|
||||
terminal.current.open(terminalRef.current);
|
||||
console.log('Terminal opened successfully.');
|
||||
} else {
|
||||
console.error('Terminal reference is not valid!');
|
||||
}
|
||||
terminal.current.open(terminalRef.current);
|
||||
fitAddon.current.fit();
|
||||
|
||||
// Fit the terminal and send the size when needed
|
||||
const fitAndNotifyResize = () => {
|
||||
fitAddon.current.fit();
|
||||
if (socket.current && socket.current.readyState === WebSocket.OPEN) {
|
||||
socket.current.send(JSON.stringify({
|
||||
cols: terminal.current.cols,
|
||||
rows: terminal.current.rows,
|
||||
}));
|
||||
}
|
||||
};
|
||||
window.addEventListener('resize', fitAndNotifyResize);
|
||||
|
||||
terminal.current.onResize(({ cols, rows }) => {
|
||||
console.log(`Terminal resized to cols:${cols}, rows:${rows}`);
|
||||
fitAndNotifyResize();
|
||||
});
|
||||
|
||||
const handleConnectionEstablished = () => {
|
||||
fitAndNotifyResize();
|
||||
};
|
||||
|
||||
window.addEventListener('connection-established', handleConnectionEstablished);
|
||||
|
||||
// Monitor terminal data (activity)
|
||||
terminal.current.onData((data) => {
|
||||
if (socket.current && socket.current.readyState === WebSocket.OPEN) {
|
||||
socket.current.send(data);
|
||||
}
|
||||
});
|
||||
|
||||
const resizeTerminal = () => {
|
||||
if (terminalRef.current) {
|
||||
fitAddon.current.fit();
|
||||
notifyServerOfResize();
|
||||
}
|
||||
};
|
||||
|
||||
const notifyServerOfResize = () => {
|
||||
if (socket.current && socket.current.readyState === WebSocket.OPEN) {
|
||||
const { rows, cols } = terminal.current;
|
||||
socket.current.send(
|
||||
JSON.stringify({
|
||||
type: 'resize',
|
||||
rows,
|
||||
cols,
|
||||
height: terminalRef.current.offsetHeight,
|
||||
width: terminalRef.current.offsetWidth,
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
resizeTerminal();
|
||||
window.addEventListener('resize', resizeTerminal);
|
||||
|
||||
return () => {
|
||||
terminal.current.dispose();
|
||||
if (socket.current) {
|
||||
socket.current.close();
|
||||
}
|
||||
window.removeEventListener('resize', resizeTerminal);
|
||||
window.removeEventListener('resize', fitAndNotifyResize);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleConnect = () => {
|
||||
console.log('Connecting...');
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const wsUrl = `${protocol}//${window.location.host}/ws/`;
|
||||
console.log(`WebSocket URL: ${wsUrl}`);
|
||||
const wsUrl = `${protocol}//${window.location.host}/ws/`; // Use current host and "/ws/" endpoint
|
||||
|
||||
if (!host || !username || !password) {
|
||||
terminal.current.writeln('Please fill in all fields.');
|
||||
return;
|
||||
}
|
||||
|
||||
socket.current = new WebSocket(wsUrl);
|
||||
|
||||
socket.current.onopen = () => {
|
||||
console.log('WebSocket connection opened');
|
||||
terminal.current.writeln(`Connected to WebSocket server at ${wsUrl}`);
|
||||
socket.current.send(JSON.stringify({ host, username, password }));
|
||||
socket.current.send(
|
||||
JSON.stringify({
|
||||
host,
|
||||
port,
|
||||
username,
|
||||
password,
|
||||
rows: terminal.current.rows,
|
||||
cols: terminal.current.cols
|
||||
})
|
||||
);
|
||||
|
||||
// Dispatch a custom event when connection is open
|
||||
const event = new Event('connection-established');
|
||||
window.dispatchEvent(event);
|
||||
|
||||
setIsConnected(true);
|
||||
};
|
||||
|
||||
socket.current.onmessage = (event) => {
|
||||
console.log('Received message:', event.data);
|
||||
terminal.current.write(event.data);
|
||||
};
|
||||
|
||||
socket.current.onerror = (error) => {
|
||||
console.error('WebSocket error:', error);
|
||||
terminal.current.writeln(`WebSocket error: ${error.message}`);
|
||||
};
|
||||
|
||||
socket.current.onclose = () => {
|
||||
console.log('WebSocket connection closed');
|
||||
terminal.current.writeln('Disconnected from WebSocket server.');
|
||||
setIsConnected(false);
|
||||
};
|
||||
@@ -112,13 +123,33 @@ const App = () => {
|
||||
};
|
||||
|
||||
const handleSideBarHiding = () => {
|
||||
setIsSideBarHidden((prevState) => !prevState);
|
||||
if (!isSideBarHidden) {
|
||||
setTimeout(() => {
|
||||
fitAddon.current.fit();
|
||||
notifyServerOfResize();
|
||||
}, 100);
|
||||
}
|
||||
setIsSideBarHidden((prevState) => {
|
||||
const newState = !prevState;
|
||||
if (newState) {
|
||||
setTimeout(() => {
|
||||
// Add a delay to ensure layout settles before resize action
|
||||
fitAddon.current.fit();
|
||||
if (socket.current && socket.current.readyState === WebSocket.OPEN) {
|
||||
socket.current.send(JSON.stringify({
|
||||
cols: terminal.current.cols,
|
||||
rows: terminal.current.rows,
|
||||
}));
|
||||
}
|
||||
}, 100); // Delay of 100 milliseconds
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
// Refit terminal when showing sidebar as well
|
||||
fitAddon.current.fit();
|
||||
if (socket.current && socket.current.readyState === WebSocket.OPEN) {
|
||||
socket.current.send(JSON.stringify({
|
||||
cols: terminal.current.cols,
|
||||
rows: terminal.current.rows,
|
||||
}));
|
||||
}
|
||||
}, 100); // Delay of 100 milliseconds
|
||||
}
|
||||
return newState;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -132,6 +163,12 @@ const App = () => {
|
||||
value={host}
|
||||
onChange={(e) => handleInputChange(e, setHost)}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Port"
|
||||
value={port}
|
||||
onChange={(e) => handleInputChange(e, setPort)}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
@@ -152,7 +189,11 @@ const App = () => {
|
||||
<div ref={terminalRef} className="terminal-container"></div>
|
||||
</div>
|
||||
|
||||
<button className="hide-sidebar-button" onClick={handleSideBarHiding}>
|
||||
{/* Hide button always positioned in the bottom-right corner */}
|
||||
<button
|
||||
className="hide-sidebar-button"
|
||||
onClick={handleSideBarHiding}
|
||||
>
|
||||
{isSideBarHidden ? '+' : '-'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ body {
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
overflow: hidden; /* Prevent scrolling */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
code {
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 49 KiB |
@@ -1,7 +1,7 @@
|
||||
// start.js
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
const child = spawn('node', ["\"D:/Programming Projects/SSH-Project-JB/backend/server.js\""], {
|
||||
const child = spawn('node', ["\"D:/Programming Projects/Termix/backend/server.js\""], {
|
||||
stdio: 'inherit', // this is key for interactivity
|
||||
shell: true, // use system shell
|
||||
});
|
||||
|
||||
0
git_push.sh
Executable file → Normal file
11
info.txt
@@ -1,11 +1,2 @@
|
||||
Currently:
|
||||
Fix issue after nano where the input no longer goes down to the bottom.
|
||||
Fix issue where SSH randomly disconnects
|
||||
Post inital build.
|
||||
|
||||
Overall Features:
|
||||
SSH/RDP(?)/VNC(?)
|
||||
Split Screen & Tabs
|
||||
ChatGPT/Ollama Stuff
|
||||
SMTP(?)
|
||||
Login Page
|
||||
Done for release!
|
||||
164
package-lock.json
generated
@@ -1,164 +0,0 @@
|
||||
{
|
||||
"name": "SSH-Project-JB",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"cross-env": "^7.0.3",
|
||||
"xterm-addon-fit": "^0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-env": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"cross-env": "src/bin/cross-env.js",
|
||||
"cross-env-shell": "src/bin/cross-env-shell.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.14",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"dependencies": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"node-which": "bin/node-which"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/xterm": {
|
||||
"version": "5.3.0",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/xterm-addon-fit": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.8.0.tgz",
|
||||
"integrity": "sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==",
|
||||
"deprecated": "This package is now deprecated. Move to @xterm/addon-fit instead.",
|
||||
"peerDependencies": {
|
||||
"xterm": "^5.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"cross-env": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
||||
"requires": {
|
||||
"cross-spawn": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||
"requires": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
|
||||
},
|
||||
"path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
|
||||
},
|
||||
"shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"requires": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"requires": {
|
||||
"isexe": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"xterm": {
|
||||
"version": "5.3.0",
|
||||
"peer": true
|
||||
},
|
||||
"xterm-addon-fit": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.8.0.tgz",
|
||||
"integrity": "sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"cross-env": "^7.0.3",
|
||||
"xterm-addon-fit": "^0.8.0"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 39 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"short_name": "Termix",
|
||||
"name": "Termix",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
|
||||
BIN
repo-images/DemoImage1.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
repo-images/TermixLogo.png
Normal file
|
After Width: | Height: | Size: 19 KiB |