Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions AppScope/app.json5
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"app": {
"bundleName": "org.electerm.electerm",
"vendor": "electerm",
"versionCode": 41500121,
"versionName": "4.15.121",
"versionCode": 31500167,
"versionName": "3.15.167",
"icon": "$media:app_icon",
"label": "$string:app_name"
}
Expand Down
2 changes: 1 addition & 1 deletion entry/oh-package.json5
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "entry",
"version": "4.15.121",
"version": "3.15.167",
"description": "Electerm HarmonyOS entry module — provides UI surface and Electron runtime integration",
"main": "",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion oh-package.json5
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "electerm-harmony",
"version": "4.15.121",
"version": "3.15.167",
"description": "Free and open-sourced ssh/sftp/telnet/RDP/VNC/Spice/ftp client for HarmonyOS",
"main": "",
"license": "MIT",
Expand Down
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "electerm-harmony",
"version": "4.15.167",
"name": "electerm",
"version": "3.15.167",
"description": "electerm — a free and open-source ssh/sftp/telnet/RDP/VNC/Spice/ftp client for HarmonyOS, built on the electerm codebase.",
"main": "app.js",
"bin": "npm/electerm",
Expand Down
17 changes: 15 additions & 2 deletions src/app/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,21 @@ function getDataPath () {
blog('app.getPath("appData") failed:', e.message)
}

// 4. Final fallback
blog('falling back to os.tmpdir():', os.tmpdir())
// 4. Final fallback — try /data/local/tmp (writable on HarmonyOS/Android),
// then os.tmpdir() as the absolute last resort.
const fallbacks = ['/data/local/tmp', os.tmpdir()]
for (const dir of fallbacks) {
try {
fs.mkdirSync(dir, { recursive: true })
blog('using fallback temp dir:', dir)
return dir
} catch (e) {
blog('fallback dir not writable:', dir, '-', e.message)
}
}

// If everything fails, return os.tmpdir() anyway — better than crashing.
blog('all fallbacks failed, returning os.tmpdir():', os.tmpdir())
return os.tmpdir()
}

Expand Down
7 changes: 5 additions & 2 deletions src/app/common/app-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ function getAppDataPath () {
}

const appDataPath = getAppDataPath()
const sshKeysPath = resolve(appDataPath, '.ssh')
// Create immediately so SSH key reads/writes never fail on a missing dir.
try { fs.mkdirSync(sshKeysPath, { recursive: true, mode: 0o700 }) } catch {}

module.exports = {
appPath: appDataPath,
isPortable: false,
exePath: '',
sshKeysPath: resolve(appDataPath, '.ssh'),
homeOrTmp: os.homedir(),
sshKeysPath,
homeOrTmp: constants.homeDir,
...constants
}
27 changes: 26 additions & 1 deletion src/app/common/runtime-constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

const os = require('os')
const fs = require('fs')
const { resolve } = require('path')

const platform = os.platform()
Expand Down Expand Up @@ -36,6 +37,29 @@ const extIconPath = isDev

const defaultUserName = require('./default-user-name')

/**
* On HarmonyOS, os.homedir() returns an inaccessible path
* (e.g. /storage/Users/currentUser) and os.tmpdir() may also point to
* a location outside the app sandbox. When process.env.DATA_PATH is set
* (by bootstrap.js), use it as the base for both home and temp dirs.
*/
function getHomeDir () {
if (process.env.DATA_PATH) {
return process.env.DATA_PATH
}
return os.homedir()
}

function getTempDir () {
if (process.env.DATA_PATH) {
const dir = resolve(process.env.DATA_PATH, 'tmp')
// Create immediately so downstream writes never fail on a missing dir.
try { fs.mkdirSync(dir, { recursive: true }) } catch {}
return dir
}
return os.tmpdir()
}

module.exports = {
isTest: !!NODE_TEST,
isDev,
Expand All @@ -50,6 +74,7 @@ module.exports = {
minWindowWidth: 590,
minWindowHeight: 400,
defaultLang: 'en_us',
tempDir: require('os').tmpdir(),
homeDir: getHomeDir(),
tempDir: getTempDir(),
packInfo: require(isDev ? '../../../package.json' : '../package.json')
}
34 changes: 5 additions & 29 deletions src/app/lib/db.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/**
* db loader
* Provides electron-related environment to nedb/sqlite modules
* Falls back to nedb (pure JS) if node:sqlite is not available (e.g. HarmonyOS)
* Uses nedb (pure JS, no native dependencies).
*/

const { appPath, defaultUserName } = require('../common/app-props')
Expand All @@ -10,31 +9,8 @@ const dlog = require('../common/debug-logger')

const encOpts = { enc: safeEncrypt, dec: safeDecrypt }

function trySqlite () {
dlog('db.js: trying node:sqlite...')
try {
require('node:sqlite')
const { createDb } = require('./sqlite')
dlog('db.js: node:sqlite available, creating db...')
const result = createDb(appPath, defaultUserName, encOpts)
dlog('db.js: sqlite db created')
return result
} catch (e) {
dlog('db.js: node:sqlite not available:', e?.message || e)
console.warn('node:sqlite not available, falling back to nedb:', e?.message || e)
return null
}
}

let db = null
dlog('db.js: node version:', process.versions.node)
if (process.versions.node >= '22.0.0') {
db = trySqlite()
}
if (!db) {
dlog('db.js: using nedb...')
const { createDb } = require('./nedb')
db = createDb(appPath, defaultUserName, encOpts)
dlog('db.js: nedb db created')
}
dlog('db.js: using nedb')
const { createDb } = require('./nedb')
const db = createDb(appPath, defaultUserName, encOpts)
dlog('db.js: nedb db created')
module.exports = db
8 changes: 2 additions & 6 deletions src/app/lib/ipc.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ const {
stopWidget,
runWidgetFunc
} = require('../widgets/load-widget')
const {
checkMigrate,
migrate
} = require('../migrate/migrate-1-to-2')
const {
setPassword,
checkPassword
Expand Down Expand Up @@ -173,8 +169,6 @@ function initIpc () {
loadFontList,
doUpgrade,
checkDbUpgrade,
checkMigrate,
migrate,
getExitStatus: () => globalState.get('exitStatus'),
setExitStatus: (status) => {
globalState.set('exitStatus', status)
Expand Down Expand Up @@ -240,6 +234,8 @@ function initIpc () {
unregisterDeepLink,
checkProtocolRegistration,
getPendingDeepLink,
checkMigrate: () => false,
migrate: () => false,
getEnv: (key) => {
if (key) {
return SAFE_ENV_KEYS.includes(key) ? process.env[key] : ''
Expand Down
4 changes: 2 additions & 2 deletions src/app/lib/single-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
const net = require('net')
const fs = require('fs')
const path = require('path')
const os = require('os')
const { app } = require('electron')
const globalState = require('./glob-state')
const { tempDir } = require('../common/runtime-constants')

function getSocketPath () {
return path.join(os.tmpdir(), `${app.getName()}-instance.sock`)
return path.join(tempDir, `${app.getName()}-instance.sock`)
}

// Clean up stale socket file
Expand Down
Loading
Loading