add random ext app (#2273)

* copy paste from afsk

* add generate thing

* todo: remove uneeded code

* todo: remove uneeded code

* todo: asycnmsg detect indicate, check way to not use global password

* removed audio

* add log warn modal

* small tune

* remove drunk code

* password var global

* seed as text instead of console

* remove console

* should be almost done

* naming fix

* bitmap now moved to seperate folder, that header i deleted isn't related to firmware

* get cmake format back

* get cmake format back - try2

* try to revert cmake file

* get cmake format back - try3

* get cmake format back - try4

* move to util

* disable amp when launch

* refactor name

* cmake fix

* try to revert cmake file

* init in methods local var

* user another methods to generate

* change pause to flood

* fix log

* fine tune

* clang format

* fix name
This commit is contained in:
zxkmm 2024-09-30 22:13:55 +08:00 committed by GitHub
parent b43eaa8786
commit 105742acbc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 683 additions and 1 deletions

View File

@ -96,6 +96,10 @@ set(EXTCPPSRC
#sstvtx #sstvtx
external/sstvtx/main.cpp external/sstvtx/main.cpp
external/sstvtx/ui_sstvtx.cpp external/sstvtx/ui_sstvtx.cpp
#random
external/random_password/main.cpp
external/random_password/ui_random_password.cpp
) )
set(EXTAPPLIST set(EXTAPPLIST
@ -122,4 +126,5 @@ set(EXTAPPLIST
adsbtx adsbtx
morse_tx morse_tx
sstvtx sstvtx
random_password
) )

View File

@ -46,6 +46,7 @@ MEMORY
ram_external_app_adsbtx(rwx) : org = 0xADC50000, len = 32k ram_external_app_adsbtx(rwx) : org = 0xADC50000, len = 32k
ram_external_app_morse_tx(rwx) : org = 0xADC60000, len = 32k ram_external_app_morse_tx(rwx) : org = 0xADC60000, len = 32k
ram_external_app_sstvtx(rwx) : org = 0xADC70000, len = 32k ram_external_app_sstvtx(rwx) : org = 0xADC70000, len = 32k
ram_external_app_random_password(rwx) : org = 0xADC80000, len = 32k
} }
SECTIONS SECTIONS
@ -190,6 +191,10 @@ SECTIONS
*(*ui*external_app*sstvtx*); *(*ui*external_app*sstvtx*);
} > ram_external_app_sstvtx } > ram_external_app_sstvtx
.external_app_random_password : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_random_password.application_information));
*(*ui*external_app*random_password*);
} > ram_external_app_random_password
} }

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2023 Bernd Herzog
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_random_password.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::random_password {
void initialize_app(ui::NavigationView& nav) {
nav.push<RandomPasswordView>();
}
} // namespace ui::external_app::random_password
extern "C" {
__attribute__((section(".external_app.app_random_password.application_information"), used)) application_information_t _application_information_random_password = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::random_password::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "random passwd",
/*.bitmap_data = */ {
0xC0,
0x03,
0xE0,
0x07,
0x30,
0x0C,
0x30,
0x0C,
0x30,
0x0C,
0x30,
0x0C,
0xE0,
0x07,
0xC0,
0x03,
0x80,
0x01,
0x80,
0x01,
0x80,
0x01,
0x80,
0x01,
0x80,
0x07,
0x80,
0x03,
0x80,
0x07,
0x80,
0x01,
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.m4_app_tag = portapack::spi_flash::image_tag_afsk_rx */ {'P', 'A', 'F', 'R'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}

View File

@ -0,0 +1,371 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* copyleft zxkmm
* Copyright (C) 2024 HToToo
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_random_password.hpp"
#include "ui_modemsetup.hpp"
#include "modems.hpp"
#include "rtc_time.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
#include "file_path.hpp"
using namespace portapack;
using namespace modems;
using namespace ui;
namespace ui::external_app::random_password {
void RandomPasswordLogger::log_raw_data(const std::string& data) {
log_file.write_entry(data);
}
void RandomPasswordView::focus() {
button_refresh.focus();
}
RandomPasswordView::RandomPasswordView(NavigationView& nav)
: nav_{nav} {
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
add_children({&rssi,
&channel,
&field_rf_amp,
&field_lna,
&field_vga,
&field_frequency,
&check_log,
&button_modem_setup,
&labels,
&text_generated_passwd,
&text_char_type_hints,
&check_digits,
&check_latin_lower,
&check_latin_upper,
&check_punctuation,
&check_show_seeds,
&check_auto_send,
&button_refresh,
&button_show_qr,
&button_flood,
&button_send,
&field_digits,
&check_allow_confusable_chars,
&text_seed,
&progressbar});
// no idea what's these, i copied from afsk rx app and they seems needed'
auto def_bell202 = &modem_defs[0];
persistent_memory::set_modem_baudrate(def_bell202->baudrate);
serial_format_t serial_format;
serial_format.data_bits = 7;
serial_format.parity = EVEN;
serial_format.stop_bits = 1;
serial_format.bit_order = LSB_FIRST;
persistent_memory::set_serial_format(serial_format);
progressbar.set_max(30);
check_log.set_value(logging);
check_log.on_select = [this](Checkbox&, bool v) {
if (v) {
nav_.display_modal(
"Warning",
"Sure?\n"
"this will save all generated\n"
"password to sdcard\n"
"in plain text\n"
"those which generated before\n"
"you check me, will lost",
YESNO,
[this, v](bool c) {
if (c) {
logging = v;
} else {
check_log.set_value(false);
// this is needed to check back to false cuz when trigger by human, the check to true already happened
// this blocked interface so won't accidently saved even if user checked but selected no later here,
// but take care of here if in the future implemented ticking/auto/batch save etc
}
});
} else {
logging = v;
}
};
button_modem_setup.on_select = [&nav](Button&) { // copied from afsk rx app
nav.push<ModemSetupView>();
};
check_digits.on_select = [this](Checkbox&, bool) {
this->new_password();
};
check_latin_lower.on_select = [this](Checkbox&, bool) {
this->new_password();
};
check_latin_upper.on_select = [this](Checkbox&, bool) {
this->new_password();
};
check_punctuation.on_select = [this](Checkbox&, bool) {
this->new_password();
};
check_allow_confusable_chars.on_select = [this](Checkbox&, bool) {
this->new_password();
};
button_refresh.on_select = [this](Button&) {
this->set_random_freq();
this->new_password();
};
button_show_qr.on_select = [this, &nav](Button&) {
nav.push<QRCodeView>(password.data());
};
button_flood.on_select = [this](Button&) {
if (flooding) {
flooding = false;
button_flood.set_text("flood");
} else {
flooding = true;
button_flood.set_text("stop");
}
};
button_send.on_select = [this, &nav](Button&) {
portapack::async_tx_enabled = true;
UsbSerialAsyncmsg::asyncmsg(password);
portapack::async_tx_enabled = false;
};
field_digits.on_change = [this](int32_t) {
clean_buffer();
this->new_password();
};
/// v check defauly val init
check_digits.set_value(true);
check_latin_lower.set_value(true);
check_latin_upper.set_value(true);
check_punctuation.set_value(true);
check_show_seeds.set_value(true);
field_digits.set_value(16);
///^ check defauly val init
logger = std::make_unique<RandomPasswordLogger>();
if (logger)
logger->append(logs_dir / u"random.TXT");
// Auto-configure modem for LCR RX (will be removed later), copied from afsk rx app
baseband::set_afsk(persistent_memory::modem_baudrate(), 8, 0, false);
receiver_model.enable();
receiver_model.set_rf_amp(false);
set_random_freq();
new_password();
}
void RandomPasswordView::on_data(uint32_t value, bool is_data) {
if (is_data) {
seed = static_cast<unsigned int>(value);
text_seed.set(to_string_dec_uint(check_show_seeds.value() ? seed : 0));
/// v feed deque
seeds_deque.push_back(value);
if (seeds_deque.size() > MAX_DIGITS) {
seeds_deque.pop_front();
}
///^ feed deque
progressbar.set_value(seeds_deque.size());
if (flooding && seeds_deque.size() >= MAX_DIGITS) {
new_password();
}
} else {
text_generated_passwd.set("Baudrate estimation: ~");
text_char_type_hints.set(to_string_dec_uint(value));
}
}
void RandomPasswordView::clean_buffer() {
seeds_deque = {};
char_deque = {""};
}
void RandomPasswordView::on_freqchg(int64_t freq) {
field_frequency.set_value(freq);
}
void RandomPasswordView::set_random_freq() {
std::srand(LPC_RTC->CTIME0);
// this is only for seed to visit random freq, the radio is still real random
auto random_freq = 100000000 + (std::rand() % 900000000); // 100mhz to 1ghz
receiver_model.set_target_frequency(random_freq);
field_frequency.set_value(random_freq);
}
void RandomPasswordView::new_password() {
if (seeds_deque.size() < MAX_DIGITS) {
seeds_buffer_not_full = true;
text_generated_passwd.set("wait seeds buffer full");
text_char_type_hints.set("then press generate");
return;
}
password = "";
std::string charset = "";
std::string char_type_hints = "";
if (check_digits.value())
charset += "0123456789";
if (check_latin_lower.value())
charset += "abcdefghijklmnopqrstuvwxyz";
if (check_latin_upper.value())
charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (check_punctuation.value())
charset += ".,-!?";
if (!check_allow_confusable_chars.value()) {
charset.erase(std::remove_if(charset.begin(), charset.end(),
[](char c) { return c == '0' || c == 'O' || c == 'o' || c == '1' || c == 'l'; }),
charset.end());
}
if (charset.empty()) {
text_generated_passwd.set("generate failed,");
text_char_type_hints.set("select at least 1 type");
return;
}
int password_length = field_digits.value();
/*the seeds_buffer were feed streaming by AFSK,
* and when generate, it use each seed for each char, and uint seeds totally can generate UINT_MAX result,
* which already cover the 10+26+25+4 (123+abc+abc+.!)
* so total possible password would be PW_LENGTH ^ (10+26+25+4), which already covered all the possible solution
* (assume AFSK data is averaged in chaotic space, which maybe no one can garentee but I hope so)
* */
for (int i = 0; i < password_length; i++) {
unsigned int seed = seeds_deque[i];
std::srand(seed);
char c = charset[std::rand() % charset.length()];
password += c;
char_deque.push_back(std::string(1, c));
if (std::isdigit(c)) {
char_type_hints += "1";
} else if (std::islower(c)) {
char_type_hints += "a";
} else if (std::isupper(c)) {
char_type_hints += "A";
} else {
char_type_hints += ",";
}
}
text_generated_passwd.set(password);
text_char_type_hints.set(char_type_hints);
paint_password_hints(); // TODO: why flash and disappeared
if (logger && logging) {
str_log += generate_log_line();
logger->log_raw_data(str_log);
str_log = "";
}
if (check_auto_send.value() || flooding) {
portapack::async_tx_enabled = true;
// printing out seeds buufer
// for (auto seed : seeds_deque) {
// UsbSerialAsyncmsg::asyncmsg(std::to_string(seed));
// }
UsbSerialAsyncmsg::asyncmsg(password);
portapack::async_tx_enabled = false;
}
clean_buffer();
}
// TODO: why flash and disappeared
// tried:
// 1. paint inline in new_password func
// 2. paint in a seperate func and call from new_password
// 3. override nav's paint func (i think it can tried to capture same obj) and paint, hoping set_dirty handle it correctly
// 4. override nav's paint func (i think it can tried to capture same obj) and paint in a seperate func, hoping set_dirty handle it correctly
// all these methods failed, and all of them only flash and disappeared. only when set_dirty in on_data (which seems incorrect), and it keep flashing never stop. but see painted content (flashing too)
// btw this is not caused by the seed text set thing, cuz commented it out not helping.
void RandomPasswordView::paint_password_hints() {
Painter painter;
const int char_width = 8;
const int char_height = 16;
const int start_y = 6 * char_height + 5;
const int rect_height = 4;
for (size_t i = 0; i < password.length(); i++) {
char c = password[i];
Color color;
if (std::isdigit(c)) {
color = Color::red();
} else if (std::islower(c)) {
color = Color::green();
} else if (std::isupper(c)) {
color = Color::blue();
} else {
color = Color::white();
}
painter.fill_rectangle(
{{static_cast<int>(i) * char_width, start_y},
{char_width, rect_height}},
color);
}
}
std::string RandomPasswordView::generate_log_line() {
std::string seeds_set = "";
for (auto seed : seeds_deque) {
seeds_set += std::to_string(seed);
seeds_set += " ";
}
std::string line = "\npassword=" + password +
"\nseeds=" + seeds_set +
"\n";
return line;
}
RandomPasswordView::~RandomPasswordView() {
receiver_model.disable();
baseband::shutdown();
}
} // namespace ui::external_app::random_password

View File

@ -0,0 +1,219 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* copyleft zxkmm
* Copyright (C) 2024 HToToo
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __UI_RANDOM_PASSWORD_H__
#define __UI_RANDOM_PASSWORD_H__
#define MAX_DIGITS 30
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "ui_freq_field.hpp"
#include "ui_record_view.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "log_file.hpp"
#include "utility.hpp"
#include "ui_qrcode.hpp"
#include "usb_serial_asyncmsg.hpp"
#include <deque>
using namespace ui;
namespace ui::external_app::random_password {
class RandomPasswordLogger { // TODO: log is broken after introduced the buffer thing
public:
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
void log_raw_data(const std::string& data);
private:
LogFile log_file{};
};
class RandomPasswordView : public View {
public:
RandomPasswordView(NavigationView& nav);
~RandomPasswordView();
void focus() override;
std::string title() const override { return "r.passwd"; };
private:
unsigned int seed = 0; // extern void srand (unsigned int __seed) __THROW;
std::string password = "";
std::deque<unsigned int> seeds_deque = {0};
std::deque<std::string> char_deque = {""};
bool seeds_buffer_not_full = true;
bool in_benchmark = false;
bool flooding = false;
bool logging = false;
std::string str_log{""};
void on_data(uint32_t value, bool is_data);
void clean_buffer();
void new_password();
std::string generate_log_line();
void paint_password_hints();
NavigationView& nav_;
RxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"rx_afsk", app_settings::Mode::RX};
Labels labels{
{{0 * 8, 0 * 16}, "------------seeds-------------", Theme::getInstance()->fg_light->foreground},
{{0 * 8, 3 * 16}, "-----------password-----------", Theme::getInstance()->fg_light->foreground},
{{5 * 8, 7 * 16 - 2}, "digits:", Theme::getInstance()->fg_light->foreground},
};
RFAmpField field_rf_amp{
{13 * 8, 1 * 16}};
LNAGainField field_lna{
{15 * 8, 1 * 16}};
VGAGainField field_vga{
{18 * 8, 1 * 16}};
RSSI rssi{
{21 * 8, 1 * 16 + 0, 6 * 8, 4}};
Channel channel{
{21 * 8, 1 * 16 + 5, 6 * 8, 4}};
RxFrequencyField field_frequency{
{0 * 8, 1 * 16},
nav_};
Button button_modem_setup{
{screen_width - 12 * 8, 2 * 16 - 1, 96, 16 + 2},
"AFSK modem"};
Text text_seed{
{0, 2 * 16, 10 * 8, 16},
"0000000000"};
ProgressBar progressbar{
{10 * 8 + 2, 2 * 16, screen_width - 96 - (10 * 8 + 4) - 1, 16}};
Text text_generated_passwd{
{0, 4 * 16, screen_width, 28},
"000000000000000000000000000000"};
Text text_char_type_hints{
{0, 5 * 16, screen_width, 28},
"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"};
Checkbox check_show_seeds{
{17 * 8, 8 * 16},
6,
"show seed"};
Checkbox check_auto_send{
{1 * 8, 8 * 16},
20,
"auto send"};
Checkbox check_punctuation{
{17 * 8, 12 * 16},
6,
".,-!?"};
Checkbox check_allow_confusable_chars{
{1 * 8, 10 * 16},
20,
"0 O o 1 l"};
Checkbox check_digits{
{1 * 8, 12 * 16},
3,
"123"};
Checkbox check_latin_lower{
{1 * 8, 14 * 16},
3,
"abc"};
Checkbox check_latin_upper{
{17 * 8, 14 * 16},
3,
"ABC"};
Checkbox check_log{
{17 * 8, 10 * 16},
3,
"savin"};
Button button_flood{
{0 * 8, 15 * 16 + 18, screen_width / 2, 22},
"flood"};
Button button_send{
{screen_width / 2 + 2, 15 * 16 + 18, screen_width / 2 - 2, 22},
"send pwd"};
Button button_refresh{
{0 * 8, 17 * 16 + 10, screen_width / 2, 22},
"generate"};
Button button_show_qr{
{screen_width / 2 + 2, 17 * 16 + 10, screen_width / 2 - 2, 22},
"show QR"};
NumberField field_digits{
{16 * 8, 7 * 16 - 2},
2,
{1, 30},
1,
' '};
void on_data_afsk(const AFSKDataMessage& message);
std::unique_ptr<RandomPasswordLogger> logger{};
MessageHandlerRegistration message_handler_packet{
Message::ID::AFSKData,
[this](Message* const p) {
const auto message = static_cast<const AFSKDataMessage*>(p);
this->on_data(message->value, message->is_data);
}};
MessageHandlerRegistration message_handler_freqchg{
Message::ID::FreqChangeCommand,
[this](Message* const p) {
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
this->on_freqchg(message->freq);
}};
void on_freqchg(int64_t freq);
void set_random_freq();
};
} // namespace ui::external_app::random_password
#endif /*__UI_RANDOM_PASSWORD_H__*/

BIN
firmware/graphics/key.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB