diff --git a/crud.py b/crud.py
index b942190..a2b1ddd 100644
--- a/crud.py
+++ b/crud.py
@@ -308,8 +308,10 @@ async def create_lamassu_config(data: CreateLamassuConfigData) -> LamassuConfig:
await db.execute(
"""
INSERT INTO myextension.lamassu_config
- (id, host, port, database_name, username, password, is_active, created_at, updated_at)
- VALUES (:id, :host, :port, :database_name, :username, :password, :is_active, :created_at, :updated_at)
+ (id, host, port, database_name, username, password, is_active, created_at, updated_at,
+ use_ssh_tunnel, ssh_host, ssh_port, ssh_username, ssh_password, ssh_private_key)
+ VALUES (:id, :host, :port, :database_name, :username, :password, :is_active, :created_at, :updated_at,
+ :use_ssh_tunnel, :ssh_host, :ssh_port, :ssh_username, :ssh_password, :ssh_private_key)
""",
{
"id": config_id,
@@ -320,7 +322,13 @@ async def create_lamassu_config(data: CreateLamassuConfigData) -> LamassuConfig:
"password": data.password,
"is_active": True,
"created_at": datetime.now(),
- "updated_at": datetime.now()
+ "updated_at": datetime.now(),
+ "use_ssh_tunnel": data.use_ssh_tunnel,
+ "ssh_host": data.ssh_host,
+ "ssh_port": data.ssh_port,
+ "ssh_username": data.ssh_username,
+ "ssh_password": data.ssh_password,
+ "ssh_private_key": data.ssh_private_key
}
)
return await get_lamassu_config(config_id)
diff --git a/migrations.py b/migrations.py
index 1048e94..7556f97 100644
--- a/migrations.py
+++ b/migrations.py
@@ -116,3 +116,45 @@ async def m006_create_lamassu_config(db):
);
"""
)
+
+
+async def m007_add_ssh_tunnel_support(db):
+ """
+ Add SSH tunnel support to Lamassu configuration table.
+ """
+ await db.execute(
+ """
+ ALTER TABLE myextension.lamassu_config
+ ADD COLUMN use_ssh_tunnel BOOLEAN NOT NULL DEFAULT false;
+ """
+ )
+ await db.execute(
+ """
+ ALTER TABLE myextension.lamassu_config
+ ADD COLUMN ssh_host TEXT;
+ """
+ )
+ await db.execute(
+ """
+ ALTER TABLE myextension.lamassu_config
+ ADD COLUMN ssh_port INTEGER NOT NULL DEFAULT 22;
+ """
+ )
+ await db.execute(
+ """
+ ALTER TABLE myextension.lamassu_config
+ ADD COLUMN ssh_username TEXT;
+ """
+ )
+ await db.execute(
+ """
+ ALTER TABLE myextension.lamassu_config
+ ADD COLUMN ssh_password TEXT;
+ """
+ )
+ await db.execute(
+ """
+ ALTER TABLE myextension.lamassu_config
+ ADD COLUMN ssh_private_key TEXT;
+ """
+ )
diff --git a/models.py b/models.py
index 5d60566..c916953 100644
--- a/models.py
+++ b/models.py
@@ -106,6 +106,13 @@ class CreateLamassuConfigData(BaseModel):
database_name: str
username: str
password: str
+ # SSH Tunnel settings
+ use_ssh_tunnel: bool = False
+ ssh_host: Optional[str] = None
+ ssh_port: int = 22
+ ssh_username: Optional[str] = None
+ ssh_password: Optional[str] = None
+ ssh_private_key: Optional[str] = None # Path to private key file or key content
class LamassuConfig(BaseModel):
@@ -120,6 +127,13 @@ class LamassuConfig(BaseModel):
test_connection_success: Optional[bool]
created_at: datetime
updated_at: datetime
+ # SSH Tunnel settings
+ use_ssh_tunnel: bool = False
+ ssh_host: Optional[str] = None
+ ssh_port: int = 22
+ ssh_username: Optional[str] = None
+ ssh_password: Optional[str] = None
+ ssh_private_key: Optional[str] = None
class UpdateLamassuConfigData(BaseModel):
@@ -129,6 +143,13 @@ class UpdateLamassuConfigData(BaseModel):
username: Optional[str] = None
password: Optional[str] = None
is_active: Optional[bool] = None
+ # SSH Tunnel settings
+ use_ssh_tunnel: Optional[bool] = None
+ ssh_host: Optional[str] = None
+ ssh_port: Optional[int] = None
+ ssh_username: Optional[str] = None
+ ssh_password: Optional[str] = None
+ ssh_private_key: Optional[str] = None
# Legacy models (keep for backward compatibility during transition)
diff --git a/static/js/index.js b/static/js/index.js
index d4d144a..0e02e66 100644
--- a/static/js/index.js
+++ b/static/js/index.js
@@ -69,7 +69,14 @@ window.app = Vue.createApp({
port: 5432,
database_name: '',
username: '',
- password: ''
+ password: '',
+ // SSH Tunnel settings
+ use_ssh_tunnel: false,
+ ssh_host: '',
+ ssh_port: 22,
+ ssh_username: '',
+ ssh_password: '',
+ ssh_private_key: ''
}
},
@@ -148,7 +155,14 @@ window.app = Vue.createApp({
port: this.configDialog.data.port,
database_name: this.configDialog.data.database_name,
username: this.configDialog.data.username,
- password: this.configDialog.data.password
+ password: this.configDialog.data.password,
+ // SSH Tunnel settings
+ use_ssh_tunnel: this.configDialog.data.use_ssh_tunnel,
+ ssh_host: this.configDialog.data.ssh_host,
+ ssh_port: this.configDialog.data.ssh_port,
+ ssh_username: this.configDialog.data.ssh_username,
+ ssh_password: this.configDialog.data.ssh_password,
+ ssh_private_key: this.configDialog.data.ssh_private_key
}
const {data: config} = await LNbits.api.request(
@@ -178,7 +192,14 @@ window.app = Vue.createApp({
port: 5432,
database_name: '',
username: '',
- password: ''
+ password: '',
+ // SSH Tunnel settings
+ use_ssh_tunnel: false,
+ ssh_host: '',
+ ssh_port: 22,
+ ssh_username: '',
+ ssh_password: '',
+ ssh_private_key: ''
}
},
@@ -640,6 +661,22 @@ window.app = Vue.createApp({
},
computed: {
+ isConfigFormValid() {
+ const data = this.configDialog.data
+
+ // Basic database fields are required
+ const basicValid = data.host && data.database_name && data.username
+
+ // If SSH tunnel is enabled, validate SSH fields
+ if (data.use_ssh_tunnel) {
+ const sshValid = data.ssh_host && data.ssh_username &&
+ (data.ssh_password || data.ssh_private_key)
+ return basicValid && sshValid
+ }
+
+ return basicValid
+ },
+
clientOptions() {
return this.dcaClients.map(client => ({
label: `${client.user_id.substring(0, 8)}... (${client.dca_mode})`,
diff --git a/templates/myextension/index.html b/templates/myextension/index.html
index f7b2577..503dc93 100644
--- a/templates/myextension/index.html
+++ b/templates/myextension/index.html
@@ -558,6 +558,83 @@
hint="Database password"
>
+