diff --git a/package/secubox/luci-app-cloner/htdocs/luci-static/resources/view/cloner/overview.js b/package/secubox/luci-app-cloner/htdocs/luci-static/resources/view/cloner/overview.js index 01e65ce8..886dfc6e 100644 --- a/package/secubox/luci-app-cloner/htdocs/luci-static/resources/view/cloner/overview.js +++ b/package/secubox/luci-app-cloner/htdocs/luci-static/resources/view/cloner/overview.js @@ -836,7 +836,22 @@ return view.extend({ renderBuildTab: function() { var self = this; var p = this.buildProgress || {}; - var isBuilding = p.building; + var isBuilding = !!p.building; + + // Build button attributes - only set disabled when building + var selectAttrs = { + 'id': 'device-type-select', + 'style': 'padding:10px;background:var(--kiss-bg2);border:1px solid var(--kiss-line);border-radius:6px;color:var(--kiss-text);font-size:14px;min-width:250px;cursor:pointer;' + }; + var buttonAttrs = { + 'class': 'kiss-btn kiss-btn-blue', + 'style': 'cursor:pointer;', + 'click': function() { self.handleBuild(); } + }; + if (isBuilding) { + selectAttrs.disabled = true; + buttonAttrs.disabled = true; + } return E('div', {}, [ // Build Controls @@ -844,18 +859,10 @@ return view.extend({ E('span', {}, '🔨 Build Clone Image') ], E('div', {}, [ E('div', { 'style': 'display:flex;gap:12px;align-items:center;flex-wrap:wrap;' }, [ - E('select', { - 'id': 'device-type-select', - 'style': 'padding:10px;background:var(--kiss-bg2);border:1px solid var(--kiss-line);border-radius:6px;color:var(--kiss-text);font-size:14px;min-width:250px;', - 'disabled': isBuilding - }, this.devices.map(function(dev) { + E('select', selectAttrs, this.devices.map(function(dev) { return E('option', { 'value': dev.id }, dev.name + ' (' + dev.cpu + ')'); })), - E('button', { - 'class': 'kiss-btn kiss-btn-blue', - 'disabled': isBuilding, - 'click': function() { self.handleBuild(); } - }, isBuilding ? ['⏳ ', 'Building...'] : ['🔨 ', 'Start Build']), + E('button', buttonAttrs, isBuilding ? ['⏳ ', 'Building...'] : ['🔨 ', 'Start Build']), isBuilding ? E('span', { 'style': 'color:var(--kiss-yellow);font-size:13px;' }, '⚠️ Build in progress...') : null ].filter(Boolean)), E('p', { 'style': 'color:var(--kiss-muted);font-size:12px;margin-top:12px;margin-bottom:0;' }, diff --git a/package/secubox/luci-app-cloner/root/usr/libexec/rpcd/luci.cloner b/package/secubox/luci-app-cloner/root/usr/libexec/rpcd/luci.cloner index 133b5033..ebea9545 100755 --- a/package/secubox/luci-app-cloner/root/usr/libexec/rpcd/luci.cloner +++ b/package/secubox/luci-app-cloner/root/usr/libexec/rpcd/luci.cloner @@ -793,7 +793,24 @@ do_scp() { # dropbear doesn't have scp, use dbclient with cat for file transfer local ip=$(echo "$dest" | cut -d':' -f1 | sed 's/root@//') local remote_path=$(echo "$dest" | cut -d':' -f2) + + # Check source file exists + [ ! -f "$src" ] && return 1 + + # Clean any stale host keys (prevents mismatch errors after device reflash) + for khfile in /root/.ssh/known_hosts /.ssh/known_hosts /overlay/upper/.ssh/known_hosts; do + [ -f "$khfile" ] && sed -i "/^$ip /d" "$khfile" 2>/dev/null + done + + # Transfer file - dbclient with -y accepts new host keys cat "$src" | dbclient -i "$SSH_KEY" -y "root@$ip" "cat > $remote_path" 2>/dev/null + local ret=$? + + # Verify file exists on remote (BusyBox compatible) + if [ $ret -eq 0 ]; then + dbclient -i "$SSH_KEY" -y "root@$ip" "[ -s $remote_path ]" 2>/dev/null && return 0 + fi + return 1 } do_list_remotes() {