@@ -1186,7 +1186,7 @@ export function App({ address, packetStore, nodeStore, skipConfig = false, skipN
11861186 }
11871187 } , [ myNodeNum , transport , configOwner , showNotification , batchEditMode , batchEditCount ] ) ;
11881188
1189- const saveChannel = useCallback ( async ( channelIndex : number , updates : { name ?: string ; role ?: number } ) => {
1189+ const saveChannel = useCallback ( async ( channelIndex : number , updates : { name ?: string ; role ?: number ; psk ?: Uint8Array ; uplinkEnabled ?: boolean ; downlinkEnabled ?: boolean } ) => {
11901190 if ( ! transport || ! myNodeNum ) return ;
11911191 const channel = configChannels . find ( c => c . index === channelIndex ) ;
11921192 if ( ! channel ) return ;
@@ -1198,6 +1198,9 @@ export function App({ address, packetStore, nodeStore, skipConfig = false, skipN
11981198 settings : create ( Mesh . ChannelSettingsSchema , {
11991199 ...channel . settings ,
12001200 name : updates . name !== undefined ? updates . name : channel . settings ?. name ,
1201+ psk : updates . psk !== undefined ? updates . psk : channel . settings ?. psk ,
1202+ uplinkEnabled : updates . uplinkEnabled !== undefined ? updates . uplinkEnabled : channel . settings ?. uplinkEnabled ,
1203+ downlinkEnabled : updates . downlinkEnabled !== undefined ? updates . downlinkEnabled : channel . settings ?. downlinkEnabled ,
12011204 } ) ,
12021205 } ) ;
12031206 const binary = adminHelper . createSetChannelRequest ( updatedChannel , { myNodeNum } ) ;
@@ -2000,11 +2003,35 @@ export function App({ address, packetStore, nodeStore, skipConfig = false, skipN
20002003 setLocalMeshViewUrl ( newUrl ) ;
20012004 showNotification ( newUrl ? `MeshView URL set to ${ newUrl } ` : "MeshView URL cleared" ) ;
20022005 } else if ( configSection === "channels" && configEditing ?. startsWith ( "channel" ) ) {
2003- // Save channel name - parse channel index from field key like "channel0_name"
2004- const match = configEditing . match ( / ^ c h a n n e l ( \d + ) _ n a m e $ / ) ;
2005- if ( match ) {
2006- const channelIndex = parseInt ( match [ 1 ] , 10 ) ;
2006+ // Save channel settings - parse channel index from field key like "channel0_name" or "channel0_psk"
2007+ const nameMatch = configEditing . match ( / ^ c h a n n e l ( \d + ) _ n a m e $ / ) ;
2008+ const pskMatch = configEditing . match ( / ^ c h a n n e l ( \d + ) _ p s k $ / ) ;
2009+ if ( nameMatch ) {
2010+ const channelIndex = parseInt ( nameMatch [ 1 ] , 10 ) ;
20072011 saveChannel ( channelIndex , { name : configEditValue } ) ;
2012+ } else if ( pskMatch ) {
2013+ const channelIndex = parseInt ( pskMatch [ 1 ] , 10 ) ;
2014+ // Parse base64 PSK
2015+ try {
2016+ const trimmed = configEditValue . trim ( ) ;
2017+ if ( trimmed === "" || trimmed === "0" ) {
2018+ // Empty or "0" means unencrypted
2019+ saveChannel ( channelIndex , { psk : new Uint8Array ( [ 0 ] ) } ) ;
2020+ } else if ( trimmed === "1" || trimmed . toLowerCase ( ) === "default" ) {
2021+ // "1" or "default" means default key
2022+ saveChannel ( channelIndex , { psk : new Uint8Array ( [ 1 ] ) } ) ;
2023+ } else {
2024+ // Try to decode as base64
2025+ const decoded = atob ( trimmed ) ;
2026+ const psk = new Uint8Array ( decoded . length ) ;
2027+ for ( let i = 0 ; i < decoded . length ; i ++ ) {
2028+ psk [ i ] = decoded . charCodeAt ( i ) ;
2029+ }
2030+ saveChannel ( channelIndex , { psk } ) ;
2031+ }
2032+ } catch {
2033+ showNotification ( "Invalid base64 key" ) ;
2034+ }
20082035 }
20092036 }
20102037 setConfigEditing ( null ) ;
@@ -2082,6 +2109,44 @@ export function App({ address, packetStore, nodeStore, skipConfig = false, skipN
20822109 }
20832110 return ;
20842111 }
2112+ // 'p' to edit PSK
2113+ if ( input === "p" ) {
2114+ const channel = validChannels [ selectedChannelIndex ] ;
2115+ if ( channel ) {
2116+ setConfigEditing ( `channel${ channel . index } _psk` ) ;
2117+ // Show current PSK as base64
2118+ const psk = channel . settings ?. psk ;
2119+ if ( psk && psk . length > 0 && ! ( psk . length === 1 && psk [ 0 ] === 0 ) ) {
2120+ const binary = String . fromCharCode ( ...psk ) ;
2121+ try {
2122+ setConfigEditValue ( btoa ( binary ) ) ;
2123+ } catch {
2124+ setConfigEditValue ( "" ) ;
2125+ }
2126+ } else {
2127+ setConfigEditValue ( "" ) ;
2128+ }
2129+ }
2130+ return ;
2131+ }
2132+ // 'u' to toggle uplink
2133+ if ( input === "u" ) {
2134+ const channel = validChannels [ selectedChannelIndex ] ;
2135+ if ( channel ) {
2136+ const newValue = ! channel . settings ?. uplinkEnabled ;
2137+ saveChannel ( channel . index , { uplinkEnabled : newValue } ) ;
2138+ }
2139+ return ;
2140+ }
2141+ // 'D' to toggle downlink (capital to avoid conflict with DM shortcut)
2142+ if ( input === "D" ) {
2143+ const channel = validChannels [ selectedChannelIndex ] ;
2144+ if ( channel ) {
2145+ const newValue = ! channel . settings ?. downlinkEnabled ;
2146+ saveChannel ( channel . index , { downlinkEnabled : newValue } ) ;
2147+ }
2148+ return ;
2149+ }
20852150 }
20862151 }
20872152 }
0 commit comments