mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-07-11 19:17:04 +10:00
Merge pull request #467 from sethoscope/set-repeater-key
Add UI for setting repeater identity keys
This commit is contained in:
+21
-1
@@ -1474,6 +1474,26 @@
|
||||
"repeater_advancedSettingsSubtitle": "Tuning knobs for experienced operators",
|
||||
"repeater_pathHashMode": "Path hash mode",
|
||||
"repeater_pathHashModeHelper": "Bytes used to encode this repeater's ID in flood path/loop-detect tags. 0=1 byte (256 IDs, up to 64 hops), 1=2 bytes (65K IDs, up to 32 hops), 2=3 bytes (16M IDs, up to 21 hops). v1.13 and older firmware drops multi-byte paths — only raise once your network is on v1.14+.",
|
||||
"repeater_keySettings": "Change Identity Keys",
|
||||
"repeater_keySettingsSubtitle": "Change the public/private keypair",
|
||||
"repeater_prvKey": "Private key",
|
||||
"repeater_prvKeyHelper": "A new private key for the repeater, a 128-character hex string.",
|
||||
"repeater_generatePrvKey": "Generate a random keypair",
|
||||
"repeater_stopGeneratingPrvKey": "Interrupt search for keypair",
|
||||
"repeater_pubKey": "Public key",
|
||||
"repeater_pubKeyHelper": "This is the public key that goes with the generated private key. You can't set this directly.",
|
||||
"repeater_pubKeyPrefix": "Desired prefix",
|
||||
"repeater_pubKeyPrefixHelper": "Find a public key that starts with these hex digits. Expected tries needed: {tries}.",
|
||||
"@repeater_pubKeyPrefixHelper": {
|
||||
"placeholders": {
|
||||
"tries": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
"repeater_txDelay": "Flood TX delay",
|
||||
"repeater_txDelayHelper": "Retransmit spacing for flood traffic, as a multiplier of the packet's airtime (0-2, default 0.5). Higher = fewer collisions but slower delivery.",
|
||||
"repeater_directTxDelay": "Direct TX delay",
|
||||
@@ -1654,7 +1674,7 @@
|
||||
"repeater_cliHelpPowersavingOnOff": "Enables or disables powersaving mode (where supported).",
|
||||
"repeater_cliHelpErase": "(Serial only) Formats the device file system. Wipes all settings and contacts.",
|
||||
"repeater_cliHelpSetDutyCycle": "Sets the maximum allowed transmit duty cycle as a percentage (1-100). Internally adjusts the airtime factor.",
|
||||
"repeater_cliHelpSetPrvKey": "(Serial only) Replaces the device identity private key. Reboot required to apply. Generates a new public key.",
|
||||
"repeater_cliHelpSetPrvKey": "Replaces the device identity private key. Reboot required to apply. Generates a new public key.",
|
||||
"repeater_cliHelpSetRadioRxGain": "(SX126x only) Toggles boosted RX gain for improved sensitivity at higher current draw.",
|
||||
"repeater_cliHelpSetOwnerInfo": "Sets the owner contact info string included in adverts. Use '|' for newlines.",
|
||||
"repeater_cliHelpSetPathHashMode": "Sets the path-hash mode. 0 = legacy, 1 = standard, 2 = strict. Affects how routing paths are matched.",
|
||||
|
||||
@@ -4844,6 +4844,66 @@ abstract class AppLocalizations {
|
||||
/// **'Bytes used to encode this repeater\'s ID in flood path/loop-detect tags. 0=1 byte (256 IDs, up to 64 hops), 1=2 bytes (65K IDs, up to 32 hops), 2=3 bytes (16M IDs, up to 21 hops). v1.13 and older firmware drops multi-byte paths — only raise once your network is on v1.14+.'**
|
||||
String get repeater_pathHashModeHelper;
|
||||
|
||||
/// No description provided for @repeater_keySettings.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Change Identity Keys'**
|
||||
String get repeater_keySettings;
|
||||
|
||||
/// No description provided for @repeater_keySettingsSubtitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Change the public/private keypair'**
|
||||
String get repeater_keySettingsSubtitle;
|
||||
|
||||
/// No description provided for @repeater_prvKey.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Private key'**
|
||||
String get repeater_prvKey;
|
||||
|
||||
/// No description provided for @repeater_prvKeyHelper.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'A new private key for the repeater, a 128-character hex string.'**
|
||||
String get repeater_prvKeyHelper;
|
||||
|
||||
/// No description provided for @repeater_generatePrvKey.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Generate a random keypair'**
|
||||
String get repeater_generatePrvKey;
|
||||
|
||||
/// No description provided for @repeater_stopGeneratingPrvKey.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Interrupt search for keypair'**
|
||||
String get repeater_stopGeneratingPrvKey;
|
||||
|
||||
/// No description provided for @repeater_pubKey.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Public key'**
|
||||
String get repeater_pubKey;
|
||||
|
||||
/// No description provided for @repeater_pubKeyHelper.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'This is the public key that goes with the generated private key. You can\'t set this directly.'**
|
||||
String get repeater_pubKeyHelper;
|
||||
|
||||
/// No description provided for @repeater_pubKeyPrefix.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Desired prefix'**
|
||||
String get repeater_pubKeyPrefix;
|
||||
|
||||
/// No description provided for @repeater_pubKeyPrefixHelper.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Find a public key that starts with these hex digits. Expected tries needed: {tries}.'**
|
||||
String repeater_pubKeyPrefixHelper(int tries);
|
||||
|
||||
/// No description provided for @repeater_txDelay.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
@@ -5615,7 +5675,7 @@ abstract class AppLocalizations {
|
||||
/// No description provided for @repeater_cliHelpSetPrvKey.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'(Serial only) Replaces the device identity private key. Reboot required to apply. Generates a new public key.'**
|
||||
/// **'Replaces the device identity private key. Reboot required to apply. Generates a new public key.'**
|
||||
String get repeater_cliHelpSetPrvKey;
|
||||
|
||||
/// No description provided for @repeater_cliHelpSetRadioRxGain.
|
||||
|
||||
@@ -2707,6 +2707,41 @@ class AppLocalizationsBg extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Забавяне на Flood TX';
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@override
|
||||
String get repeater_txDelayHelper =>
|
||||
|
||||
@@ -2701,6 +2701,41 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Bytes, die zur Kodierung der ID dieses Repeaters in Flood-Pfad-/Schleifen-Erkennung-Tags verwendet werden. 0 = 1 Byte (256 IDs, bis zu 64 Hops), 1 = 2 Bytes (65.000 IDs, bis zu 32 Hops), 2 = 3 Bytes (16 Millionen IDs, bis zu 21 Hops). Firmware-Versionen 1.13 und älter verwenden mehrstellige Pfade – ab Version 1.14+ wird nur ein Pfad erstellt, sobald das Netzwerk aktiv ist.';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Flood-TX-Verzögerung';
|
||||
|
||||
|
||||
@@ -2655,6 +2655,41 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Bytes used to encode this repeater\'s ID in flood path/loop-detect tags. 0=1 byte (256 IDs, up to 64 hops), 1=2 bytes (65K IDs, up to 32 hops), 2=3 bytes (16M IDs, up to 21 hops). v1.13 and older firmware drops multi-byte paths — only raise once your network is on v1.14+.';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Flood TX delay';
|
||||
|
||||
@@ -3125,7 +3160,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get repeater_cliHelpSetPrvKey =>
|
||||
'(Serial only) Replaces the device identity private key. Reboot required to apply. Generates a new public key.';
|
||||
'Replaces the device identity private key. Reboot required to apply. Generates a new public key.';
|
||||
|
||||
@override
|
||||
String get repeater_cliHelpSetRadioRxGain =>
|
||||
|
||||
@@ -2700,6 +2700,41 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Bytes utilizados para codificar el ID de este repetidor en las etiquetas de ruta/detección de bucles. 0=1 byte (256 IDs, hasta 64 saltos), 1=2 bytes (65.000 IDs, hasta 32 saltos), 2=3 bytes (16 millones de IDs, hasta 21 saltos). Las versiones 1.13 y anteriores de firmware eliminan rutas de múltiples bytes; solo se detectan una vez que la red está activa en la versión 1.14 o posterior.';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Retraso TX por inundación';
|
||||
|
||||
|
||||
@@ -2711,6 +2711,41 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Octets utilisés pour encoder l\'ID de ce routeur dans les balises de détection de flux/boucles. 0 = 1 octet (256 ID, jusqu\'à 64 sauts), 1 = 2 octets (65 000 ID, jusqu\'à 32 sauts), 2 = 3 octets (16 millions d\'ID, jusqu\'à 21 sauts). Les versions 1.13 et antérieures utilisent des chemins multi-octets ; à partir de la version 1.14, cela n\'est plus nécessaire.';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Délai de transmission en flood';
|
||||
|
||||
|
||||
@@ -2694,6 +2694,41 @@ class AppLocalizationsHu extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Az átjátszó azonosítójának elárasztási útvonal/hurokészlelési címkékbe való kódolására használt bájtok. 0 = 1 bájt (256 azonosító, legfeljebb 64 ugrás), 1 = 2 bájt (65 000 azonosító, legfeljebb 32 ugrás), 2 = 3 bájt (16 millió azonosító, legfeljebb 21 ugrás). A v1.13 és régebbi firmware eldobja a többbájtos elérési utat – csak akkor emelje meg, ha a hálózat a v1.14+ verziót használja.';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Áradási TX késleltetés';
|
||||
|
||||
|
||||
@@ -2702,6 +2702,41 @@ class AppLocalizationsIt extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Byte utilizzati per codificare l\'ID di questo ripetitore nei tag per il rilevamento del percorso/loop. 0=1 byte (256 ID, fino a 64 salti), 1=2 byte (65.000 ID, fino a 32 salti), 2=3 byte (16 milioni di ID, fino a 21 salti). Le versioni 1.13 e precedenti utilizzano percorsi multi-byte: è necessario attivare la rete prima di utilizzare questa funzionalità (a partire dalla versione 1.14).';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Ritardo a Flood, TX';
|
||||
|
||||
|
||||
@@ -2583,6 +2583,41 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'このリピータのIDをフローパス/ループ検出タグにエンコードするために使用されるバイト数。 0=1バイト (256個のID、最大64ホップ)、1=2バイト (65,000個のID、最大32ホップ)、2=3バイト (160万個のID、最大21ホップ)。 v1.13およびそれ以前のファームウェアでは、マルチバイトパスがサポートされていません。 v1.14以降のバージョンでは、一度ネットワークが起動されると、パスが一度だけ検出されます。';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'フロイド・TXでの遅延';
|
||||
|
||||
|
||||
@@ -2589,6 +2589,41 @@ class AppLocalizationsKo extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'이 리피터의 ID를 플러드 경로/루프 감지 태그에 인코딩하는 데 사용되는 바이트 수: 0=1 바이트 (256개의 ID, 최대 64개의 홉), 1=2 바이트 (65,000개의 ID, 최대 32개의 홉), 2=3 바이트 (16백만 개의 ID, 최대 21개의 홉). v1.13 및 이전 버전의 펌웨어는 다중 바이트 경로를 지원하지 않으며, 네트워크가 v1.14 이상으로 업그레이드되면 한 번만 감지합니다.';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => '플러드 TX 지연';
|
||||
|
||||
|
||||
@@ -2683,6 +2683,41 @@ class AppLocalizationsNl extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Bytes die gebruikt worden om de ID van deze repeater te coderen in flood-pad/lusdetectietags. 0=1 byte (256 ID\'s, tot 64 hops), 1=2 bytes (65.000 ID\'s, tot 32 hops), 2=3 bytes (16 miljoen ID\'s, tot 21 hops). Versies 1.13 en ouder gebruiken multi-byte paden – alleen na het activeren van het netwerk.';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Vertraging bij Flood TX';
|
||||
|
||||
|
||||
@@ -2716,6 +2716,41 @@ class AppLocalizationsPl extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Bity wykorzystywane do kodowania identyfikatora tego urządzenia w tagach ścieżek/detekcji pętli. 0=1 bity (256 identyfikatorów, do 64 skoków), 1=2 bity (65 000 identyfikatorów, do 32 skoków), 2=3 bity (1 600 000 identyfikatorów, do 21 skoków). Wersje 1.13 i wcześniejsze nie obsługują ścieżek wielobitowych – wykrywają tylko jedną, gdy sieć jest w wersji 1.14 lub nowszej.';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Opóźnienie w Flood, TX';
|
||||
|
||||
|
||||
@@ -2701,6 +2701,41 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Bytes utilizados para codificar o ID deste repetidor nas tags de caminho/detecção de loop. 0=1 byte (256 IDs, até 64 saltos), 1=2 bytes (65.000 IDs, até 32 saltos), 2=3 bytes (16 milhões de IDs, até 21 saltos). As versões 1.13 e anteriores do firmware não suportam caminhos multi-byte — apenas funcionam uma vez após a ativação da rede (a partir da versão 1.14+).';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Atraso na entrega em Flood, TX';
|
||||
|
||||
|
||||
@@ -2706,6 +2706,41 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Байты, используемые для кодирования идентификатора этого ретранслятора в тегах для обнаружения потоков/циклов. 0 = 1 байт (256 идентификаторов, до 64 переходов), 1 = 2 байта (65 000 идентификаторов, до 32 переходов), 2 = 3 байта (1 600 000 идентификаторов, до 21 перехода). Версии прошивки v1.13 и более ранние версии не поддерживают многобайтовые пути — они поднимаются только после того, как ваша сеть будет обновлена до версии v1.14 и выше.';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Задержка в работе системы Flood TX';
|
||||
|
||||
|
||||
@@ -2687,6 +2687,41 @@ class AppLocalizationsSk extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Byty použité na zakódovanie ID tohto opakovača v tagoch pre trasu/detekciu slučky. 0 = 1 bytu (256 ID, až 64 skokov), 1 = 2 byty (65 000 ID, až 32 skokov), 2 = 3 byty (16 miliónov ID, až 21 skokov). Verzie 1.13 a staršie nepodporujú viacbytové trasy – fungujú len, keď je sieť aktivovaná.';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Zpoždanie v Flood, TX';
|
||||
|
||||
|
||||
@@ -2683,6 +2683,41 @@ class AppLocalizationsSl extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Biti, ki so bila uporabljena za kodiranje ID-ja tega releja v oznakah za zaznavanje pot/kroga, imajo naslednje velikosti: 0=1 bit (256 ID-jev, do 64 skokov), 1=2 biti (65.000 ID-jev, do 32 skokov), 2=3 biti (16 milijonov ID-jev, do 21 skokov). V različicah 1.13 in starejših se ustvarjajo večbitne poti – vendar se to zgodi šele, ko je omrežje vklopljeno v različicah 1.14 in kasnejših.';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Zatemnitevanje zaradi poplav v Texasu';
|
||||
|
||||
|
||||
@@ -2671,6 +2671,41 @@ class AppLocalizationsSv extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Byte används för att koda denna repeaters ID i taggar för att upptäcka loopar/flödesvägar. 0=1 byte (256 ID:n, upp till 64 hopp), 1=2 byte (65 000 ID:n, upp till 32 hopp), 2=3 byte (16 miljoner ID:n, upp till 21 hopp). Versioner 1.13 och äldre har stöd för multi-byte-vägar – endast en gång när nätverket är aktiverat (från och med version 1.14).';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Försening i Flood TX';
|
||||
|
||||
|
||||
@@ -2703,6 +2703,41 @@ class AppLocalizationsUk extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'Байти, що використовуються для кодування ідентифікатора цього ретранслятора в тегах для виявлення потоків/петлі. 0=1 байт (256 ідентифікаторів, до 64 перехідів), 1=2 байти (65 000 ідентифікаторів, до 32 перехідів), 2=3 байти (16 мільйонів ідентифікаторів, до 21 переходу). Версії 1.13 та старіші не підтримують багатобайтні шляхи — вони активуються лише після того, як мережа буде оновлена до версії 1.14+.';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => 'Затримка у Flood, штат Техас';
|
||||
|
||||
|
||||
@@ -2558,6 +2558,41 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
String get repeater_pathHashModeHelper =>
|
||||
'用于编码此复用器的 ID 的字节数,在“洪流路径/环检测”标签中使用。 0=1 字节(256 个 ID,最多 64 个跳跃),1=2 字节(65K 个 ID,最多 32 个跳跃),2=3 字节(16M 个 ID,最多 21 个跳跃)。 v1.13 及更早版本的固件会使用多字节路径——只有在您的网络升级到 v1.14 或更高版本后才会生效。';
|
||||
|
||||
@override
|
||||
String get repeater_keySettings => 'Change Identity Keys';
|
||||
|
||||
@override
|
||||
String get repeater_keySettingsSubtitle =>
|
||||
'Change the public/private keypair';
|
||||
|
||||
@override
|
||||
String get repeater_prvKey => 'Private key';
|
||||
|
||||
@override
|
||||
String get repeater_prvKeyHelper =>
|
||||
'A new private key for the repeater, a 128-character hex string.';
|
||||
|
||||
@override
|
||||
String get repeater_generatePrvKey => 'Generate a random keypair';
|
||||
|
||||
@override
|
||||
String get repeater_stopGeneratingPrvKey => 'Interrupt search for keypair';
|
||||
|
||||
@override
|
||||
String get repeater_pubKey => 'Public key';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyHelper =>
|
||||
'This is the public key that goes with the generated private key. You can\'t set this directly.';
|
||||
|
||||
@override
|
||||
String get repeater_pubKeyPrefix => 'Desired prefix';
|
||||
|
||||
@override
|
||||
String repeater_pubKeyPrefixHelper(int tries) {
|
||||
return 'Find a public key that starts with these hex digits. Expected tries needed: $tries.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get repeater_txDelay => '洪水(德克萨斯州)延误';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:crypto/crypto.dart' as crypto;
|
||||
import 'package:meshcore_open/utils/keys.dart';
|
||||
|
||||
import 'channel.dart';
|
||||
|
||||
@@ -37,11 +37,7 @@ class Community {
|
||||
|
||||
/// Generate a new community with a random 32-byte secret
|
||||
factory Community.create({required String id, required String name}) {
|
||||
final random = Random.secure();
|
||||
final secret = Uint8List(32);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
secret[i] = random.nextInt(256);
|
||||
}
|
||||
final secret = randomBytes(32);
|
||||
return Community(
|
||||
id: id,
|
||||
name: name,
|
||||
@@ -210,12 +206,7 @@ class Community {
|
||||
|
||||
/// Create a copy of this community with a regenerated random secret
|
||||
Community withRegeneratedSecret() {
|
||||
final random = Random.secure();
|
||||
final newSecret = Uint8List(32);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
newSecret[i] = random.nextInt(256);
|
||||
}
|
||||
return withNewSecret(newSecret);
|
||||
return withNewSecret(randomBytes(32));
|
||||
}
|
||||
|
||||
/// Extract secret from QR data (for updating existing community)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:meshcore_open/storage/channel_message_store.dart';
|
||||
import 'package:meshcore_open/utils/keys.dart';
|
||||
import 'package:meshcore_open/utils/platform_info.dart';
|
||||
import 'package:meshcore_open/widgets/app_bar.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -938,11 +938,7 @@ class _ChannelsScreenState extends State<ChannelsScreen>
|
||||
);
|
||||
return;
|
||||
}
|
||||
final random = Random.secure();
|
||||
final psk = Uint8List(16);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
psk[i] = random.nextInt(256);
|
||||
}
|
||||
final psk = randomBytes(16);
|
||||
Navigator.pop(sheetContext);
|
||||
await connector.setChannel(
|
||||
nextIndex,
|
||||
@@ -1571,11 +1567,7 @@ class _ChannelsScreenState extends State<ChannelsScreen>
|
||||
icon: const Icon(Icons.casino),
|
||||
tooltip: sheetContext.l10n.channels_generateRandomPsk,
|
||||
onPressed: () {
|
||||
final random = Random.secure();
|
||||
final bytes = Uint8List(16);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
bytes[i] = random.nextInt(256);
|
||||
}
|
||||
final bytes = randomBytes(16);
|
||||
pskController.text = Channel.formatPskHex(bytes);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:math';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../l10n/l10n.dart';
|
||||
import '../models/contact.dart';
|
||||
@@ -11,6 +12,7 @@ import '../services/storage_service.dart';
|
||||
import '../theme/mesh_theme.dart';
|
||||
import '../widgets/mesh_ui.dart';
|
||||
import '../widgets/routing_sheet.dart';
|
||||
import '../utils/keys.dart';
|
||||
import '../helpers/snack_bar_builder.dart';
|
||||
|
||||
class RepeaterSettingsScreen extends StatefulWidget {
|
||||
@@ -44,6 +46,7 @@ enum _SettingField {
|
||||
advertInterval,
|
||||
floodAdvertInterval,
|
||||
pathHashMode,
|
||||
prvKey,
|
||||
txDelay,
|
||||
directTxDelay,
|
||||
intThresh,
|
||||
@@ -109,6 +112,8 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
||||
bool _refreshingIntThresh = false;
|
||||
bool _refreshingAgcResetInterval = false;
|
||||
bool _runningAction = false;
|
||||
bool _searchingForKeyPair = false;
|
||||
bool _stopSearchingForKeyPair = false;
|
||||
StreamSubscription<Uint8List>? _frameSubscription;
|
||||
RepeaterCommandService? _commandService;
|
||||
|
||||
@@ -154,6 +159,11 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
||||
|
||||
// Advanced
|
||||
int _pathHashMode = 0; // 0-2
|
||||
final TextEditingController _prvKeyController = TextEditingController();
|
||||
final TextEditingController _pubKeyController = TextEditingController();
|
||||
final TextEditingController _prvKeyPrefixController = TextEditingController();
|
||||
final KeyPairSearcher _keyPairSearcher = KeyPairSearcher();
|
||||
final int _searchChunkTime = 30; // time in ms to search before yielding
|
||||
final TextEditingController _txDelayController = TextEditingController();
|
||||
final TextEditingController _directTxDelayController =
|
||||
TextEditingController();
|
||||
@@ -206,6 +216,10 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
||||
_txDelayController.dispose();
|
||||
_directTxDelayController.dispose();
|
||||
_intThreshController.dispose();
|
||||
_prvKeyController.dispose();
|
||||
_pubKeyController.dispose();
|
||||
_prvKeyPrefixController.dispose();
|
||||
_stopSearchingForKeyPair = true;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -860,6 +874,12 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
||||
command: 'set path.hash.mode $_pathHashMode',
|
||||
));
|
||||
}
|
||||
if (_dirtyFields.contains(_SettingField.prvKey)) {
|
||||
final v = _prvKeyController.text.trim();
|
||||
if (v != "") {
|
||||
pending.add((field: _SettingField.prvKey, command: 'set prv.key $v'));
|
||||
}
|
||||
}
|
||||
if (_dirtyFields.contains(_SettingField.txDelay) &&
|
||||
_txDelayController.text.isNotEmpty) {
|
||||
final v = double.tryParse(_txDelayController.text.trim());
|
||||
@@ -1005,6 +1025,36 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
void _startSearchingForKeyPair() async {
|
||||
if (_searchingForKeyPair) return;
|
||||
setState(() {
|
||||
_searchingForKeyPair = true;
|
||||
_stopSearchingForKeyPair = false;
|
||||
});
|
||||
_searchForKeyPair();
|
||||
}
|
||||
|
||||
void _searchForKeyPair() async {
|
||||
if (_stopSearchingForKeyPair) {
|
||||
if (mounted) setState(() => _searchingForKeyPair = false);
|
||||
return;
|
||||
}
|
||||
final String prefix = _prvKeyPrefixController.text.trim();
|
||||
MCKeyPair? keys = await _keyPairSearcher.findMatchingKeyPair(
|
||||
prefix,
|
||||
_searchChunkTime,
|
||||
);
|
||||
if (keys == null) {
|
||||
// Ran out of time; schedule another attempt.
|
||||
Timer.run(_searchForKeyPair);
|
||||
} else {
|
||||
setState(() => _searchingForKeyPair = false);
|
||||
_prvKeyController.text = pubKeyToHex(keys.private);
|
||||
_pubKeyController.text = pubKeyToHex(keys.public);
|
||||
_markChanged(_SettingField.prvKey);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildInlineRefreshButton({
|
||||
required bool isRefreshing,
|
||||
required VoidCallback onRefresh,
|
||||
@@ -1069,6 +1119,7 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
||||
_buildOwnerInfoCard(),
|
||||
_buildActionsCard(),
|
||||
_buildAdvancedCard(),
|
||||
_buildKeysCard(),
|
||||
const SizedBox(height: 16),
|
||||
_buildDangerZoneCard(),
|
||||
],
|
||||
@@ -1984,6 +2035,127 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildKeysCard() {
|
||||
final l10n = context.l10n;
|
||||
return MeshCard(
|
||||
child: ExpansionTile(
|
||||
leading: const Icon(Icons.vpn_key),
|
||||
title: Text(
|
||||
l10n.repeater_keySettings,
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600),
|
||||
),
|
||||
subtitle: Text(l10n.repeater_keySettingsSubtitle),
|
||||
childrenPadding: const EdgeInsets.fromLTRB(0, 8, 0, 4),
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _prvKeyController,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp("[0-9a-fA-F]")),
|
||||
],
|
||||
decoration: InputDecoration(
|
||||
labelText: l10n.repeater_prvKey,
|
||||
helperText: l10n.repeater_prvKeyHelper,
|
||||
helperMaxLines: 3,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
onChanged: (_) {
|
||||
_pubKeyController.text = "";
|
||||
if (_prvKeyController.text.isNotEmpty) {
|
||||
_markChanged(_SettingField.prvKey);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: _searchingForKeyPair
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.cancel, size: 24),
|
||||
onPressed: (() => _stopSearchingForKeyPair = true),
|
||||
tooltip: l10n.repeater_stopGeneratingPrvKey,
|
||||
visualDensity: VisualDensity.compact,
|
||||
)
|
||||
: IconButton(
|
||||
icon: const Icon(Icons.casino_rounded, size: 24),
|
||||
onPressed: () {
|
||||
_startSearchingForKeyPair();
|
||||
},
|
||||
tooltip: l10n.repeater_generatePrvKey,
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
readOnly: true,
|
||||
controller: _pubKeyController,
|
||||
style: TextStyle(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).textTheme.headlineSmall?.color?.withValues(alpha: 0.6),
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
labelText: l10n.repeater_pubKey,
|
||||
helperText: l10n.repeater_pubKeyHelper,
|
||||
helperMaxLines: 3,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: _searchingForKeyPair
|
||||
? CircularProgressIndicator(strokeWidth: 2)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _prvKeyPrefixController,
|
||||
maxLength: 4,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp("[0-9a-fA-F]")),
|
||||
],
|
||||
onChanged: (_) => setState(() => {}), // updates helper text
|
||||
decoration: InputDecoration(
|
||||
labelText: l10n.repeater_pubKeyPrefix,
|
||||
helperText: l10n.repeater_pubKeyPrefixHelper(
|
||||
pow(16, _prvKeyPrefixController.text.length).toInt(),
|
||||
),
|
||||
helperMaxLines: 3,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 48),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDangerZoneCard() {
|
||||
final l10n = context.l10n;
|
||||
return MeshCard(
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'package:convert/convert.dart';
|
||||
import 'package:cryptography/cryptography.dart';
|
||||
|
||||
Uint8List randomBytes(int length) {
|
||||
final random = Random.secure();
|
||||
final bytes = Uint8List(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
bytes[i] = random.nextInt(256);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
class MCKeyPair {
|
||||
final Uint8List public;
|
||||
final Uint8List private;
|
||||
MCKeyPair(this.public, this.private);
|
||||
}
|
||||
|
||||
Future<MCKeyPair> generateKeyPair() async {
|
||||
final algo = Ed25519();
|
||||
final seed = randomBytes(32);
|
||||
final SimpleKeyPair keys = await algo.newKeyPairFromSeed(seed);
|
||||
final Uint8List pubKeyBytes = Uint8List.fromList(
|
||||
(await keys.extractPublicKey()).bytes,
|
||||
);
|
||||
// Ed25519 gives 32-byte public and private keys, but MeshCore
|
||||
// uses an expanded 64-byte private key, so we have to make it
|
||||
// ourselves. Luckily, we can do it such that it has the same public
|
||||
// key, which we'd otherwise be unable to compute, since although the
|
||||
// crypto library implements the elliptic curve computations we need,
|
||||
// it doesn't make them available.
|
||||
final Uint8List hash = Uint8List.fromList((await Sha512().hash(seed)).bytes);
|
||||
hash[0] &= 248; // Clamp the scalar. This keeps the chosen point in the
|
||||
hash[31] &= 63; // large elliptic curve subgroup, and is demanded both by
|
||||
hash[31] |= 64; // Ed25519 and by the MeshCore repeater key validation code.
|
||||
return MCKeyPair(pubKeyBytes, hash);
|
||||
}
|
||||
|
||||
class _KeyHashPrefix {
|
||||
Uint8List _bytes = Uint8List(0);
|
||||
Uint8List _mask = Uint8List(0);
|
||||
_KeyHashPrefix(String prefix) {
|
||||
final bool lengthIsOdd = (prefix.length % 2 == 1) ? true : false;
|
||||
final String decodableString = lengthIsOdd ? "${prefix}0" : prefix;
|
||||
_bytes = hex.decoder.convert(decodableString);
|
||||
_mask = Uint8List(_bytes.length);
|
||||
for (var i = 0; i < _mask.length; i++) {
|
||||
_mask[i] = 0xff;
|
||||
}
|
||||
if (lengthIsOdd) {
|
||||
_mask[_mask.length - 1] = 0xf0;
|
||||
}
|
||||
}
|
||||
|
||||
bool matches(List<int> keyBytes) {
|
||||
if (keyBytes.length < _bytes.length) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < _bytes.length; i++) {
|
||||
if (keyBytes[i] & _mask[i] != _bytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class KeyPairSearcher {
|
||||
Future<MCKeyPair?> findMatchingKeyPair(
|
||||
String prefixStr,
|
||||
int maxMilliseconds,
|
||||
) async {
|
||||
final int now = DateTime.now().millisecondsSinceEpoch;
|
||||
final int endTime = now + maxMilliseconds;
|
||||
final _KeyHashPrefix keyHashPrefix = _KeyHashPrefix(prefixStr);
|
||||
while (DateTime.now().millisecondsSinceEpoch < endTime) {
|
||||
final MCKeyPair keys = await generateKeyPair();
|
||||
if (keyHashPrefix.matches(keys.public)) {
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import cryptography_flutter
|
||||
import flutter_blue_plus_darwin
|
||||
import flutter_local_notifications
|
||||
import mobile_scanner
|
||||
@@ -15,6 +16,7 @@ import sqflite_darwin
|
||||
import url_launcher_macos
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
CryptographyFlutterPlugin.register(with: registry.registrar(forPlugin: "CryptographyFlutterPlugin"))
|
||||
FlutterBluePlusPlugin.register(with: registry.registrar(forPlugin: "FlutterBluePlusPlugin"))
|
||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
|
||||
|
||||
@@ -73,6 +73,9 @@ dependencies:
|
||||
ml_dataframe: ^1.0.0
|
||||
llamadart: ^0.8.0
|
||||
flutter_langdetect: ^0.0.1
|
||||
cryptography: ^2.9.0
|
||||
cryptography_flutter: ^2.3.4
|
||||
convert: ^3.1.2
|
||||
|
||||
hooks:
|
||||
user_defines:
|
||||
|
||||
+187
-17
@@ -15,13 +15,33 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"de": [
|
||||
"settings_regionFetchRegions",
|
||||
"settings_regionFetchRegionsFail",
|
||||
"settings_regionFetchRegionsAlreadyExists"
|
||||
"settings_regionFetchRegionsAlreadyExists",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"es": [
|
||||
@@ -40,7 +60,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"fr": [
|
||||
@@ -59,7 +89,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"hu": [
|
||||
@@ -78,7 +118,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"it": [
|
||||
@@ -97,7 +147,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"ja": [
|
||||
@@ -116,7 +176,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"ko": [
|
||||
@@ -135,7 +205,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"nl": [
|
||||
@@ -154,7 +234,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"pl": [
|
||||
@@ -173,7 +263,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"pt": [
|
||||
@@ -192,7 +292,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"ru": [
|
||||
@@ -211,7 +321,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"sk": [
|
||||
@@ -230,7 +350,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"sl": [
|
||||
@@ -249,7 +379,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"sv": [
|
||||
@@ -268,7 +408,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"uk": [
|
||||
@@ -287,7 +437,17 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
],
|
||||
|
||||
"zh": [
|
||||
@@ -306,6 +466,16 @@
|
||||
"channels_regionSetTo",
|
||||
"channels_regionNotSet",
|
||||
"channels_regionSelect_Title",
|
||||
"channels_clearRegion"
|
||||
"channels_clearRegion",
|
||||
"repeater_keySettings",
|
||||
"repeater_keySettingsSubtitle",
|
||||
"repeater_prvKey",
|
||||
"repeater_prvKeyHelper",
|
||||
"repeater_generatePrvKey",
|
||||
"repeater_stopGeneratingPrvKey",
|
||||
"repeater_pubKey",
|
||||
"repeater_pubKeyHelper",
|
||||
"repeater_pubKeyPrefix",
|
||||
"repeater_pubKeyPrefixHelper"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user