[FL-2121] U2F GUI (#942)
* U2F: new gui * U2F: user cert key encryption * FuriCore: move type casting to dangerous_defines * FuriCore: exclude dangerous things from furi.h Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									2cbf99e15a
								
							
						
					
					
						commit
						7e2f0fcc22
					
				@ -15,6 +15,9 @@
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <gui/icon_i.h>
 | 
			
		||||
 | 
			
		||||
// Read documentation before using it
 | 
			
		||||
#include <furi/dangerous_defines.h>
 | 
			
		||||
 | 
			
		||||
#define ANIMATION_META_FILE "meta.txt"
 | 
			
		||||
#define ANIMATION_DIR "/ext/dolphin/animations"
 | 
			
		||||
#define ANIMATION_MANIFEST_FILE ANIMATION_DIR "/manifest.txt"
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,8 @@
 | 
			
		||||
#include "furi-hal.h"
 | 
			
		||||
#include "../u2f.h"
 | 
			
		||||
 | 
			
		||||
#define U2F_EVENT_TIMEOUT 500
 | 
			
		||||
#define U2F_REQUEST_TIMEOUT 500
 | 
			
		||||
#define U2F_SUCCESS_TIMEOUT 3000
 | 
			
		||||
 | 
			
		||||
static void u2f_scene_main_ok_callback(InputType type, void* context) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
@ -18,8 +19,14 @@ static void u2f_scene_main_event_callback(U2fNotifyEvent evt, void* context) {
 | 
			
		||||
        view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventRegister);
 | 
			
		||||
    else if(evt == U2fNotifyAuth)
 | 
			
		||||
        view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventAuth);
 | 
			
		||||
    else if(evt == U2fNotifyAuthSuccess)
 | 
			
		||||
        view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventAuthSuccess);
 | 
			
		||||
    else if(evt == U2fNotifyWink)
 | 
			
		||||
        view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventWink);
 | 
			
		||||
    else if(evt == U2fNotifyConnect)
 | 
			
		||||
        view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventConnect);
 | 
			
		||||
    else if(evt == U2fNotifyDisconnect)
 | 
			
		||||
        view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventDisconnect);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void u2f_scene_main_timer_callback(void* context) {
 | 
			
		||||
@ -34,28 +41,39 @@ bool u2f_scene_main_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    bool consumed = false;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if((event.event == U2fCustomEventRegister) || (event.event == U2fCustomEventAuth)) {
 | 
			
		||||
            osTimerStart(app->timer, U2F_EVENT_TIMEOUT);
 | 
			
		||||
        if(event.event == U2fCustomEventConnect) {
 | 
			
		||||
            osTimerStop(app->timer);
 | 
			
		||||
            u2f_view_set_state(app->u2f_view, U2fMsgIdle);
 | 
			
		||||
        } else if(event.event == U2fCustomEventDisconnect) {
 | 
			
		||||
            osTimerStop(app->timer);
 | 
			
		||||
            app->event_cur = U2fCustomEventNone;
 | 
			
		||||
            u2f_view_set_state(app->u2f_view, U2fMsgNotConnected);
 | 
			
		||||
        } else if((event.event == U2fCustomEventRegister) || (event.event == U2fCustomEventAuth)) {
 | 
			
		||||
            osTimerStart(app->timer, U2F_REQUEST_TIMEOUT);
 | 
			
		||||
            if(app->event_cur == U2fCustomEventNone) {
 | 
			
		||||
                app->event_cur = event.event;
 | 
			
		||||
                if(event.event == U2fCustomEventRegister)
 | 
			
		||||
                    u2f_view_set_state(app->u2f_view, U2fMsgRegister);
 | 
			
		||||
                else if(event.event == U2fCustomEventAuth)
 | 
			
		||||
                    u2f_view_set_state(app->u2f_view, U2fMsgAuth);
 | 
			
		||||
                notification_message(app->notifications, &sequence_success);
 | 
			
		||||
                notification_message(app->notifications, &sequence_display_on);
 | 
			
		||||
                notification_message(app->notifications, &sequence_single_vibro);
 | 
			
		||||
            }
 | 
			
		||||
            notification_message(app->notifications, &sequence_blink_blue_10);
 | 
			
		||||
        } else if(event.event == U2fCustomEventWink) {
 | 
			
		||||
            notification_message(app->notifications, &sequence_blink_green_10);
 | 
			
		||||
        } else if(event.event == U2fCustomEventAuthSuccess) {
 | 
			
		||||
            osTimerStart(app->timer, U2F_SUCCESS_TIMEOUT);
 | 
			
		||||
            app->event_cur = U2fCustomEventNone;
 | 
			
		||||
            u2f_view_set_state(app->u2f_view, U2fMsgSuccess);
 | 
			
		||||
        } else if(event.event == U2fCustomEventTimeout) {
 | 
			
		||||
            app->event_cur = U2fCustomEventNone;
 | 
			
		||||
            u2f_view_set_state(app->u2f_view, U2fMsgNone);
 | 
			
		||||
            u2f_view_set_state(app->u2f_view, U2fMsgIdle);
 | 
			
		||||
        } else if(event.event == U2fCustomEventConfirm) {
 | 
			
		||||
            if(app->event_cur != U2fCustomEventNone) {
 | 
			
		||||
                u2f_confirm_user_present(app->u2f_instance);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        consumed = true;
 | 
			
		||||
    } else if(event.type == SceneManagerEventTypeTick) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -299,10 +299,12 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
 | 
			
		||||
    uint8_t signature_len = u2f_der_encode_signature(resp->signature, signature);
 | 
			
		||||
    memcpy(resp->signature + signature_len, state_no_error, 2);
 | 
			
		||||
 | 
			
		||||
    FURI_LOG_I(TAG, "Counter: %lu", U2F->counter);
 | 
			
		||||
    FURI_LOG_D(TAG, "Counter: %lu", U2F->counter);
 | 
			
		||||
    U2F->counter++;
 | 
			
		||||
    u2f_data_cnt_write(U2F->counter);
 | 
			
		||||
 | 
			
		||||
    if(U2F->callback != NULL) U2F->callback(U2fNotifyAuthSuccess, U2F->context);
 | 
			
		||||
 | 
			
		||||
    return (sizeof(U2fAuthResp) + signature_len + 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -330,3 +332,12 @@ uint16_t u2f_msg_parse(U2fData* U2F, uint8_t* buf, uint16_t len) {
 | 
			
		||||
void u2f_wink(U2fData* U2F) {
 | 
			
		||||
    if(U2F->callback != NULL) U2F->callback(U2fNotifyWink, U2F->context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void u2f_set_state(U2fData* U2F, uint8_t state) {
 | 
			
		||||
    if(state == 0) {
 | 
			
		||||
        if(U2F->callback != NULL) U2F->callback(U2fNotifyDisconnect, U2F->context);
 | 
			
		||||
    } else {
 | 
			
		||||
        if(U2F->callback != NULL) U2F->callback(U2fNotifyConnect, U2F->context);
 | 
			
		||||
    }
 | 
			
		||||
    U2F->user_present = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,10 @@ extern "C" {
 | 
			
		||||
typedef enum {
 | 
			
		||||
    U2fNotifyRegister,
 | 
			
		||||
    U2fNotifyAuth,
 | 
			
		||||
    U2fNotifyAuthSuccess,
 | 
			
		||||
    U2fNotifyWink,
 | 
			
		||||
    U2fNotifyConnect,
 | 
			
		||||
    U2fNotifyDisconnect,
 | 
			
		||||
} U2fNotifyEvent;
 | 
			
		||||
 | 
			
		||||
typedef struct U2fData U2fData;
 | 
			
		||||
@ -30,6 +33,8 @@ uint16_t u2f_msg_parse(U2fData* instance, uint8_t* buf, uint16_t len);
 | 
			
		||||
 | 
			
		||||
void u2f_wink(U2fData* instance);
 | 
			
		||||
 | 
			
		||||
void u2f_set_state(U2fData* instance, uint8_t state);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -17,8 +17,12 @@
 | 
			
		||||
typedef enum {
 | 
			
		||||
    U2fCustomEventNone,
 | 
			
		||||
 | 
			
		||||
    U2fCustomEventConnect,
 | 
			
		||||
    U2fCustomEventDisconnect,
 | 
			
		||||
 | 
			
		||||
    U2fCustomEventRegister,
 | 
			
		||||
    U2fCustomEventAuth,
 | 
			
		||||
    U2fCustomEventAuthSuccess,
 | 
			
		||||
    U2fCustomEventWink,
 | 
			
		||||
 | 
			
		||||
    U2fCustomEventTimeout,
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,8 @@
 | 
			
		||||
 | 
			
		||||
#define U2F_CERT_STOCK 0 // Stock certificate, private key is encrypted with factory key
 | 
			
		||||
#define U2F_CERT_USER 1 // User certificate, private key is encrypted with unique key
 | 
			
		||||
#define U2F_CERT_USER_UNENCRYPTED \
 | 
			
		||||
    2 // Unencrypted user certificate, will be encrypted after first load
 | 
			
		||||
 | 
			
		||||
#define U2F_CERT_KEY_FILE_TYPE "Flipper U2F Certificate Key File"
 | 
			
		||||
#define U2F_CERT_KEY_VERSION 1
 | 
			
		||||
@ -92,6 +94,52 @@ uint32_t u2f_data_cert_load(uint8_t* cert) {
 | 
			
		||||
    return len_cur;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool u2f_data_cert_key_encrypt(uint8_t* cert_key) {
 | 
			
		||||
    furi_assert(cert_key);
 | 
			
		||||
 | 
			
		||||
    bool state = false;
 | 
			
		||||
    uint8_t iv[16];
 | 
			
		||||
    uint8_t key[48];
 | 
			
		||||
    uint32_t cert_type = U2F_CERT_USER;
 | 
			
		||||
 | 
			
		||||
    FURI_LOG_I(TAG, "Encrypting user cert key");
 | 
			
		||||
 | 
			
		||||
    // Generate random IV
 | 
			
		||||
    furi_hal_random_fill_buf(iv, 16);
 | 
			
		||||
 | 
			
		||||
    if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) {
 | 
			
		||||
        FURI_LOG_E(TAG, "Unable to load encryption key");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(!furi_hal_crypto_encrypt(cert_key, key, 32)) {
 | 
			
		||||
        FURI_LOG_E(TAG, "Encryption failed");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
 | 
			
		||||
 | 
			
		||||
    Storage* storage = furi_record_open("storage");
 | 
			
		||||
    FlipperFile* flipper_file = flipper_file_alloc(storage);
 | 
			
		||||
 | 
			
		||||
    if(flipper_file_open_always(flipper_file, U2F_CERT_KEY_FILE)) {
 | 
			
		||||
        do {
 | 
			
		||||
            if(!flipper_file_write_header_cstr(
 | 
			
		||||
                   flipper_file, U2F_CERT_KEY_FILE_TYPE, U2F_CERT_KEY_VERSION))
 | 
			
		||||
                break;
 | 
			
		||||
            if(!flipper_file_write_uint32(flipper_file, "Type", &cert_type, 1)) break;
 | 
			
		||||
            if(!flipper_file_write_hex(flipper_file, "IV", iv, 16)) break;
 | 
			
		||||
            if(!flipper_file_write_hex(flipper_file, "Data", key, 48)) break;
 | 
			
		||||
            state = true;
 | 
			
		||||
        } while(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    flipper_file_close(flipper_file);
 | 
			
		||||
    flipper_file_free(flipper_file);
 | 
			
		||||
    furi_record_close("storage");
 | 
			
		||||
 | 
			
		||||
    return state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool u2f_data_cert_key_load(uint8_t* cert_key) {
 | 
			
		||||
    furi_assert(cert_key);
 | 
			
		||||
 | 
			
		||||
@ -133,11 +181,13 @@ bool u2f_data_cert_key_load(uint8_t* cert_key) {
 | 
			
		||||
                key_slot = U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_FACTORY;
 | 
			
		||||
            } else if(cert_type == U2F_CERT_USER) {
 | 
			
		||||
                key_slot = U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE;
 | 
			
		||||
            } else if(cert_type == U2F_CERT_USER_UNENCRYPTED) {
 | 
			
		||||
                key_slot = 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                FURI_LOG_E(TAG, "Unknown cert type");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(key_slot != 0) {
 | 
			
		||||
                if(!flipper_file_read_hex(flipper_file, "IV", iv, 16)) {
 | 
			
		||||
                    FURI_LOG_E(TAG, "Missing IV");
 | 
			
		||||
                    break;
 | 
			
		||||
@ -160,6 +210,12 @@ bool u2f_data_cert_key_load(uint8_t* cert_key) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                furi_hal_crypto_store_unload_key(key_slot);
 | 
			
		||||
            } else {
 | 
			
		||||
                if(!flipper_file_read_hex(flipper_file, "Data", cert_key, 32)) {
 | 
			
		||||
                    FURI_LOG_E(TAG, "Missing data");
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            state = true;
 | 
			
		||||
        } while(0);
 | 
			
		||||
    }
 | 
			
		||||
@ -169,6 +225,10 @@ bool u2f_data_cert_key_load(uint8_t* cert_key) {
 | 
			
		||||
    furi_record_close("storage");
 | 
			
		||||
    string_clear(filetype);
 | 
			
		||||
 | 
			
		||||
    if(cert_type == U2F_CERT_USER_UNENCRYPTED) {
 | 
			
		||||
        return u2f_data_cert_key_encrypt(cert_key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -249,9 +309,6 @@ bool u2f_data_key_generate(uint8_t* device_key) {
 | 
			
		||||
    }
 | 
			
		||||
    furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
 | 
			
		||||
 | 
			
		||||
    string_t filetype;
 | 
			
		||||
    string_init(filetype);
 | 
			
		||||
 | 
			
		||||
    Storage* storage = furi_record_open("storage");
 | 
			
		||||
    FlipperFile* flipper_file = flipper_file_alloc(storage);
 | 
			
		||||
 | 
			
		||||
@ -270,7 +327,6 @@ bool u2f_data_key_generate(uint8_t* device_key) {
 | 
			
		||||
    flipper_file_close(flipper_file);
 | 
			
		||||
    flipper_file_free(flipper_file);
 | 
			
		||||
    furi_record_close("storage");
 | 
			
		||||
    string_clear(filetype);
 | 
			
		||||
 | 
			
		||||
    return state;
 | 
			
		||||
}
 | 
			
		||||
@ -356,9 +412,6 @@ bool u2f_data_cnt_write(uint32_t cnt_val) {
 | 
			
		||||
    }
 | 
			
		||||
    furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
 | 
			
		||||
 | 
			
		||||
    string_t filetype;
 | 
			
		||||
    string_init(filetype);
 | 
			
		||||
 | 
			
		||||
    Storage* storage = furi_record_open("storage");
 | 
			
		||||
    FlipperFile* flipper_file = flipper_file_alloc(storage);
 | 
			
		||||
 | 
			
		||||
@ -376,7 +429,6 @@ bool u2f_data_cnt_write(uint32_t cnt_val) {
 | 
			
		||||
    flipper_file_close(flipper_file);
 | 
			
		||||
    flipper_file_free(flipper_file);
 | 
			
		||||
    furi_record_close("storage");
 | 
			
		||||
    string_clear(filetype);
 | 
			
		||||
 | 
			
		||||
    return state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -128,7 +128,7 @@ static void u2f_hid_send_error(U2fHid* u2f_hid, uint8_t error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool u2f_hid_parse_request(U2fHid* u2f_hid) {
 | 
			
		||||
    FURI_LOG_I(
 | 
			
		||||
    FURI_LOG_D(
 | 
			
		||||
        WORKER_TAG,
 | 
			
		||||
        "Req cid=%lX cmd=%x len=%u",
 | 
			
		||||
        u2f_hid->packet.cid,
 | 
			
		||||
@ -188,7 +188,7 @@ static int32_t u2f_hid_worker(void* context) {
 | 
			
		||||
    U2fHid* u2f_hid = context;
 | 
			
		||||
    uint8_t packet_buf[HID_U2F_PACKET_LEN];
 | 
			
		||||
 | 
			
		||||
    FURI_LOG_I(WORKER_TAG, "Init");
 | 
			
		||||
    FURI_LOG_D(WORKER_TAG, "Init");
 | 
			
		||||
 | 
			
		||||
    UsbInterface* usb_mode_prev = furi_hal_usb_get_config();
 | 
			
		||||
    furi_hal_usb_set_config(&usb_hid_u2f);
 | 
			
		||||
@ -204,8 +204,14 @@ static int32_t u2f_hid_worker(void* context) {
 | 
			
		||||
            osWaitForever);
 | 
			
		||||
        furi_check((flags & osFlagsError) == 0);
 | 
			
		||||
        if(flags & WorkerEvtStop) break;
 | 
			
		||||
        if(flags & WorkerEvtConnect) FURI_LOG_I(WORKER_TAG, "Connect");
 | 
			
		||||
        if(flags & WorkerEvtDisconnect) FURI_LOG_I(WORKER_TAG, "Disconnect");
 | 
			
		||||
        if(flags & WorkerEvtConnect) {
 | 
			
		||||
            u2f_set_state(u2f_hid->u2f_instance, 1);
 | 
			
		||||
            FURI_LOG_D(WORKER_TAG, "Connect");
 | 
			
		||||
        }
 | 
			
		||||
        if(flags & WorkerEvtDisconnect) {
 | 
			
		||||
            u2f_set_state(u2f_hid->u2f_instance, 0);
 | 
			
		||||
            FURI_LOG_D(WORKER_TAG, "Disconnect");
 | 
			
		||||
        }
 | 
			
		||||
        if(flags & WorkerEvtRequest) {
 | 
			
		||||
            uint32_t len_cur = furi_hal_hid_u2f_get_request(packet_buf);
 | 
			
		||||
            if(len_cur > 0) {
 | 
			
		||||
@ -265,7 +271,7 @@ static int32_t u2f_hid_worker(void* context) {
 | 
			
		||||
 | 
			
		||||
    furi_hal_hid_u2f_set_callback(NULL, NULL);
 | 
			
		||||
    furi_hal_usb_set_config(usb_mode_prev);
 | 
			
		||||
    FURI_LOG_I(WORKER_TAG, "End");
 | 
			
		||||
    FURI_LOG_D(WORKER_TAG, "End");
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14,22 +14,32 @@ typedef struct {
 | 
			
		||||
static void u2f_view_draw_callback(Canvas* canvas, void* _model) {
 | 
			
		||||
    U2fModel* model = _model;
 | 
			
		||||
 | 
			
		||||
    canvas_set_font(canvas, FontPrimary);
 | 
			
		||||
    canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "U2F Demo");
 | 
			
		||||
    canvas_draw_icon(canvas, 8, 14, &I_Drive_112x35);
 | 
			
		||||
    canvas_set_font(canvas, FontSecondary);
 | 
			
		||||
 | 
			
		||||
    if(model->display_msg == U2fMsgRegister) {
 | 
			
		||||
        canvas_set_font(canvas, FontPrimary);
 | 
			
		||||
        canvas_draw_str_aligned(canvas, 0, 45, AlignLeft, AlignBottom, "Registration");
 | 
			
		||||
        canvas_set_font(canvas, FontSecondary);
 | 
			
		||||
        canvas_draw_str_aligned(canvas, 0, 63, AlignLeft, AlignBottom, "Press [OK] to confirm");
 | 
			
		||||
    if(model->display_msg == U2fMsgNotConnected) {
 | 
			
		||||
        canvas_draw_icon(canvas, 22, 15, &I_Connect_me_62x31);
 | 
			
		||||
        canvas_draw_str_aligned(
 | 
			
		||||
            canvas, 128 / 2, 3, AlignCenter, AlignTop, "Connect me to computer");
 | 
			
		||||
    } else if(model->display_msg == U2fMsgIdle) {
 | 
			
		||||
        canvas_draw_icon(canvas, 22, 15, &I_Connected_62x31);
 | 
			
		||||
        canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Connected!");
 | 
			
		||||
    } else if(model->display_msg == U2fMsgRegister) {
 | 
			
		||||
        elements_button_center(canvas, "OK");
 | 
			
		||||
        canvas_draw_icon(canvas, 22, 15, &I_Auth_62x31);
 | 
			
		||||
        canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Press OK to register");
 | 
			
		||||
    } else if(model->display_msg == U2fMsgAuth) {
 | 
			
		||||
        canvas_set_font(canvas, FontPrimary);
 | 
			
		||||
        canvas_draw_str_aligned(canvas, 0, 45, AlignLeft, AlignBottom, "Authentication");
 | 
			
		||||
        canvas_set_font(canvas, FontSecondary);
 | 
			
		||||
        canvas_draw_str_aligned(canvas, 0, 63, AlignLeft, AlignBottom, "Press [OK] to confirm");
 | 
			
		||||
        elements_button_center(canvas, "OK");
 | 
			
		||||
        canvas_draw_icon(canvas, 22, 15, &I_Auth_62x31);
 | 
			
		||||
        canvas_draw_str_aligned(
 | 
			
		||||
            canvas, 128 / 2, 3, AlignCenter, AlignTop, "Press OK to authenticate");
 | 
			
		||||
    } else if(model->display_msg == U2fMsgSuccess) {
 | 
			
		||||
        canvas_draw_icon(canvas, 22, 15, &I_Connected_62x31);
 | 
			
		||||
        canvas_draw_str_aligned(
 | 
			
		||||
            canvas, 128 / 2, 3, AlignCenter, AlignTop, "Authentication successfull!");
 | 
			
		||||
    } else if(model->display_msg == U2fMsgError) {
 | 
			
		||||
        canvas_set_font(canvas, FontPrimary);
 | 
			
		||||
        canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignCenter, "U2F data missing");
 | 
			
		||||
        canvas_draw_icon(canvas, 22, 15, &I_Error_62x31);
 | 
			
		||||
        canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Ceritficate missing");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,9 +6,11 @@ typedef struct U2fView U2fView;
 | 
			
		||||
typedef void (*U2fOkCallback)(InputType type, void* context);
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    U2fMsgNone,
 | 
			
		||||
    U2fMsgNotConnected,
 | 
			
		||||
    U2fMsgIdle,
 | 
			
		||||
    U2fMsgRegister,
 | 
			
		||||
    U2fMsgAuth,
 | 
			
		||||
    U2fMsgSuccess,
 | 
			
		||||
    U2fMsgError,
 | 
			
		||||
} U2fViewMsg;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -631,6 +631,21 @@ const uint8_t *_I_Scanning_123x52[] = {_I_Scanning_123x52_0};
 | 
			
		||||
const uint8_t _I_Unlock_7x8_0[] = {0x00,0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,};
 | 
			
		||||
const uint8_t *_I_Unlock_7x8[] = {_I_Unlock_7x8_0};
 | 
			
		||||
 | 
			
		||||
const uint8_t _I_Auth_62x31_0[] = {0x01,0x00,0xaf,0x00,0x00,0x47,0xc2,0xfe,0x07,0x58,0x66,0x02,0x02,0x07,0x48,0x1c,0x02,0x0c,0x06,0x3c,0x00,0x08,0x61,0x00,0x73,0xa0,0x00,0x86,0x20,0x02,0x1b,0x04,0x02,0x40,0x04,0x10,0x11,0x01,0xc4,0x18,0x40,0x72,0xf0,0x40,0x40,0xe4,0x1a,0x20,0x38,0xc2,0x3e,0x00,0x71,0xbc,0x05,0xca,0x11,0x08,0x80,0xe0,0x30,0xc0,0x72,0x82,0x7d,0x20,0x44,0x81,0x80,0x81,0xcb,0x75,0x05,0x02,0x08,0x1c,0xe7,0x50,0x58,0xc0,0x94,0x40,0xe5,0xfa,0x82,0xc1,0xbf,0x06,0xc1,0x80,0x40,0x80,0xe3,0x00,0xbe,0x40,0x3f,0x10,0x18,0x17,0xd0,0xd0,0x33,0xf3,0xa0,0xc0,0xe0,0x52,0x88,0x26,0x02,0x3e,0x1d,0x18,0x14,0x08,0xa0,0x3c,0x08,0x78,0x3c,0xc0,0xe3,0xe0,0x83,0x87,0xcd,0x32,0x42,0x11,0x17,0x90,0x04,0x61,0x9f,0xf8,0x06,0x20,0x0e,0x41,0xb1,0x9e,0x1b,0x44,0x2e,0x5f,0x0f,0xfc,0x0c,0x0e,0x80,0x02,0x80,0xc1,0x00,0xe8,0xab,0x11,0xf9,0x01,0xca,0xe0,0x07,0x68,0x60,0xb4,0x40,0xe7,0xfe,0x1f,0x88,0x1d,0x09,0x82,0x28,0x10,0xba,0x01,0xcc,};
 | 
			
		||||
const uint8_t *_I_Auth_62x31[] = {_I_Auth_62x31_0};
 | 
			
		||||
 | 
			
		||||
const uint8_t _I_Connect_me_62x31_0[] = {0x01,0x00,0xb7,0x00,0x00,0x47,0xc2,0xfe,0x07,0x58,0x66,0x02,0x02,0x07,0x48,0x1c,0x02,0x0c,0x06,0x3c,0x00,0x08,0x61,0x00,0x73,0xa0,0x00,0x86,0x20,0x02,0x1b,0xe4,0x02,0x40,0x04,0x10,0x11,0x51,0x01,0x86,0x07,0x2b,0x60,0x1c,0xc3,0x44,0x0f,0x18,0x47,0xc0,0x0e,0x37,0x80,0xf9,0x42,0x21,0x10,0x1c,0x06,0x1a,0x01,0x82,0x80,0x41,0x3e,0x90,0x22,0x40,0xc0,0x40,0xe5,0xba,0x82,0xd8,0x20,0x00,0x73,0x9d,0x41,0x63,0x1e,0x00,0x39,0xfe,0xa0,0xb0,0x6f,0xc0,0x7c,0xa0,0x40,0x71,0x16,0x90,0x1c,0xbe,0x86,0x81,0x9f,0x81,0xce,0x51,0x04,0xc0,0x47,0xe0,0x1f,0xe0,0x38,0x94,0x07,0x81,0x0f,0x80,0x4a,0x00,0xe7,0xe0,0x83,0x81,0xcd,0x32,0x42,0x11,0x03,0x9c,0x0a,0x19,0xff,0x80,0x4e,0x00,0xe5,0x0c,0x81,0xcf,0x20,0x21,0xc1,0x03,0x8f,0xc3,0xff,0x03,0x80,0x92,0x44,0x3e,0x40,0x01,0x80,0xc1,0x20,0x60,0x73,0x55,0x8c,0x0a,0x08,0x07,0x3b,0x80,0x1c,0x61,0x00,0x73,0x86,0x11,0x48,0x0e,0x5f,0xe1,0xf8,0xc3,0x00,0xe7,0xf8,0x6c,0x0c,0x42,0x40,0x17,0x30,0x38,0xcc,0x24,0x00,};
 | 
			
		||||
const uint8_t *_I_Connect_me_62x31[] = {_I_Connect_me_62x31_0};
 | 
			
		||||
 | 
			
		||||
const uint8_t _I_Connected_62x31_0[] = {0x01,0x00,0xaa,0x00,0x00,0x47,0xc2,0xfe,0x07,0x58,0x66,0x02,0x02,0x07,0x48,0x1c,0x02,0x0c,0x06,0x3c,0x00,0x08,0x61,0x00,0x73,0xa0,0x00,0x86,0x20,0x07,0x39,0x00,0x09,0x01,0x88,0x07,0x70,0xd1,0x09,0x0b,0xe0,0x07,0x1b,0xc0,0x1c,0xe1,0x10,0x1c,0x06,0x18,0x0e,0x50,0x4f,0xa4,0x08,0x90,0x24,0x92,0x82,0x6e,0xa0,0xb6,0x08,0x07,0x04,0x10,0x30,0x49,0xd4,0x16,0x31,0xe0,0xa0,0xfc,0x80,0xe3,0xfa,0x82,0xc1,0xbf,0x14,0x08,0x64,0x06,0x04,0x07,0x18,0x05,0xf2,0x81,0x04,0x81,0x40,0xbe,0x86,0x81,0x9f,0xe0,0x20,0x80,0x81,0x94,0x41,0x30,0x11,0xf0,0x39,0x94,0x07,0x81,0x0f,0x03,0xaf,0x82,0x0f,0x00,0x84,0x81,0xc5,0x32,0x42,0x11,0x98,0x89,0xc6,0x01,0x02,0x86,0x7f,0xc9,0x03,0x03,0x03,0x8c,0x32,0x07,0x3c,0x2c,0x08,0x3c,0xbe,0x1f,0xf8,0x18,0x1d,0x00,0x05,0x81,0x0e,0x08,0x1c,0xf0,0x0a,0xc1,0x03,0xa5,0xc0,0x0e,0xd0,0xc4,0xc8,0x81,0xcf,0xfd,0x03,0x03,0xaf,0xe2,0x02,0xb1,0x10,0xba,0x01,0xcc,};
 | 
			
		||||
const uint8_t *_I_Connected_62x31[] = {_I_Connected_62x31_0};
 | 
			
		||||
 | 
			
		||||
const uint8_t _I_Drive_112x35_0[] = {0x01,0x00,0x72,0x00,0xf0,0x7f,0xc0,0x0f,0x1f,0x06,0x94,0x40,0x2f,0x12,0x00,0x19,0x42,0x01,0xb1,0x40,0x01,0x94,0x10,0x1b,0x18,0x00,0x19,0x41,0x81,0xb9,0x07,0x06,0xc9,0x24,0x81,0xb4,0x02,0x20,0x6f,0x83,0x66,0x7c,0x0d,0xc9,0x10,0x6f,0xc1,0xbe,0x0d,0xf2,0x9f,0x83,0x7c,0x14,0x3f,0x8f,0xff,0xe4,0x1b,0x4c,0xe1,0xc4,0x83,0x6a,0x1f,0x00,0xc7,0x8d,0xfc,0xc3,0xe0,0xdf,0x06,0xfa,0xd7,0xc3,0x7e,0x99,0xf0,0x6d,0x7f,0xc0,0x02,0x0d,0xcb,0xf8,0x37,0x27,0xe3,0x7c,0x80,0x2a,0x84,0x00,0xf4,0x00,0x19,0x47,0xc1,0xb1,0x20,0x01,0x97,0xf8,0x92,0x40,0x05,0x0b,0x9f,0xf0,0x1b,0x03,0x33,0x7f,0x08,0x01,0xc9,0xe6,};
 | 
			
		||||
const uint8_t *_I_Drive_112x35[] = {_I_Drive_112x35_0};
 | 
			
		||||
 | 
			
		||||
const uint8_t _I_Error_62x31_0[] = {0x01,0x00,0x9e,0x00,0x00,0x47,0xc2,0xfe,0x07,0x58,0x66,0x02,0x02,0x07,0x48,0x1c,0x02,0x0c,0x06,0x3c,0x00,0x08,0x61,0x00,0x73,0xa0,0x00,0x86,0x20,0x07,0x39,0x00,0x09,0x01,0x88,0x07,0x70,0xd1,0x09,0x0b,0xe0,0x07,0x38,0x1c,0x62,0x11,0x08,0x80,0x8c,0x8a,0x0f,0x1c,0x82,0x7d,0x20,0x58,0x0b,0xe4,0x02,0x1d,0x0e,0x82,0x6e,0xa0,0xb8,0x0c,0x1c,0x02,0x39,0x07,0x82,0x4e,0xa0,0xb7,0x08,0x04,0x07,0x71,0x03,0x82,0x7e,0xa0,0xb0,0xe8,0x04,0x0b,0xe1,0x01,0x81,0x01,0xc6,0x01,0xc0,0x81,0xf8,0x01,0x42,0x27,0x18,0x04,0xc0,0x1e,0x63,0x71,0x3d,0x0c,0x08,0x3e,0x20,0xa1,0x22,0x94,0x08,0x5e,0x21,0x51,0x0f,0x08,0xbc,0x47,0xe2,0x07,0x29,0x81,0x40,0x49,0xe2,0x07,0x28,0x61,0x80,0x4b,0xe2,0x07,0x28,0x19,0xe0,0xc0,0xe2,0x0d,0x18,0xc0,0x1d,0x00,0x02,0xa8,0x30,0x39,0x2e,0x10,0x0e,0x5e,0x00,0x3b,0x7e,0x00,0xec,0x46,0x10,0x3f,0x80,0xc8,};
 | 
			
		||||
const uint8_t *_I_Error_62x31[] = {_I_Error_62x31_0};
 | 
			
		||||
 | 
			
		||||
const uint8_t _I_DolphinExcited_64x63_0[] = {0x01,0x00,0x36,0x01,0x00,0x25,0x00,0x0f,0xd2,0x00,0x3b,0xe0,0x00,0xeb,0x10,0x0c,0x34,0x40,0x30,0xd0,0x88,0x80,0x1d,0xa1,0x00,0x42,0xfc,0x7f,0xc0,0x63,0x04,0x01,0x0e,0x02,0x0f,0x00,0x00,0x8c,0x08,0x0e,0x37,0x00,0x10,0xc6,0x20,0x10,0x10,0xd9,0x11,0x92,0x1c,0x1a,0x3e,0x00,0x04,0x42,0x02,0x1a,0x20,0xb0,0xce,0x00,0x64,0x07,0x20,0x59,0x16,0x50,0x36,0x45,0x94,0x84,0x78,0x20,0x60,0x75,0x8e,0x43,0x06,0x63,0x3c,0x33,0x94,0x0c,0xd2,0x5c,0x30,0x38,0xe4,0x08,0x43,0x10,0xc0,0x5e,0x06,0x22,0x53,0x1a,0x02,0x08,0x7f,0xd0,0x32,0xc1,0x50,0x21,0x14,0x0e,0x70,0x1c,0x46,0xe2,0x07,0x19,0x06,0x3c,0xdc,0x20,0x91,0xae,0x01,0xcc,0xbe,0x30,0x09,0xfc,0x12,0x41,0xff,0x83,0xcc,0x0a,0xa3,0x1f,0x03,0x99,0xe8,0x7c,0x10,0xf8,0x25,0xa0,0x5e,0x50,0x0f,0x84,0x1e,0x09,0x54,0x03,0x9f,0xf2,0x07,0x02,0xd5,0x11,0xca,0x01,0xfe,0x80,0xc0,0xaa,0x9f,0xf0,0x39,0x5f,0xd0,0x43,0xaa,0x83,0x41,0x92,0xc3,0x1f,0x03,0x8d,0x52,0x02,0x2e,0x25,0xc9,0x6a,0x99,0x46,0xa6,0x2a,0xa0,0x1c,0xaf,0xca,0x62,0x94,0x28,0xcb,0x7e,0x0f,0x15,0x71,0xf8,0x3c,0x22,0x71,0x03,0x8a,0x84,0x67,0x18,0x0f,0xac,0x1c,0x0e,0x38,0x08,0x0c,0x3e,0x01,0xae,0xbd,0x13,0x0c,0x0e,0x35,0x8e,0xa8,0x1c,0xb0,0x1f,0xf8,0x06,0x83,0xf4,0x27,0x38,0x07,0xff,0xff,0x8f,0x03,0xa0,0x4c,0x80,0xed,0x60,0x03,0xb4,0x60,0x0e,0xd0,0x60,0x3a,0x87,0x84,0x0e,0xb7,0xc2,0xfa,0x18,0x05,0x44,0x20,0x73,0xff,0xf7,0xce,0xe4,0x07,0x2d,0x52,0x2c,0x80,0xe7,0x54,0xea,0x81,0xd7,0x50,0x0f,0x7a,0xaa,0x3d,0x41,0xe2,0x07,0x5a,0x80,0x3c,0xa0,0x40,0x72,0xd0,0x6a,0x80,0xa2,0x07,0x3a,0x05,0x54,0x8e,0x20,0x73,0xc0,0x03,0xd8,0x60,0x30,0x40,0x3a,0xc0,0x00,0xee,0xea,0x10,0x3b,0x80,};
 | 
			
		||||
const uint8_t *_I_DolphinExcited_64x63[] = {_I_DolphinExcited_64x63_0};
 | 
			
		||||
 | 
			
		||||
@ -829,6 +844,11 @@ const Icon I_MHz_25x11 = {.width=25,.height=11,.frame_count=1,.frame_rate=0,.fra
 | 
			
		||||
const Icon I_Quest_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Quest_7x8};
 | 
			
		||||
const Icon I_Scanning_123x52 = {.width=123,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Scanning_123x52};
 | 
			
		||||
const Icon I_Unlock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Unlock_7x8};
 | 
			
		||||
const Icon I_Auth_62x31 = {.width=62,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_Auth_62x31};
 | 
			
		||||
const Icon I_Connect_me_62x31 = {.width=62,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_Connect_me_62x31};
 | 
			
		||||
const Icon I_Connected_62x31 = {.width=62,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_Connected_62x31};
 | 
			
		||||
const Icon I_Drive_112x35 = {.width=112,.height=35,.frame_count=1,.frame_rate=0,.frames=_I_Drive_112x35};
 | 
			
		||||
const Icon I_Error_62x31 = {.width=62,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_Error_62x31};
 | 
			
		||||
const Icon I_DolphinExcited_64x63 = {.width=64,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinExcited_64x63};
 | 
			
		||||
const Icon I_DolphinMafia_115x62 = {.width=115,.height=62,.frame_count=1,.frame_rate=0,.frames=_I_DolphinMafia_115x62};
 | 
			
		||||
const Icon I_DolphinNice_96x59 = {.width=96,.height=59,.frame_count=1,.frame_rate=0,.frames=_I_DolphinNice_96x59};
 | 
			
		||||
 | 
			
		||||
@ -178,6 +178,11 @@ extern const Icon I_MHz_25x11;
 | 
			
		||||
extern const Icon I_Quest_7x8;
 | 
			
		||||
extern const Icon I_Scanning_123x52;
 | 
			
		||||
extern const Icon I_Unlock_7x8;
 | 
			
		||||
extern const Icon I_Auth_62x31;
 | 
			
		||||
extern const Icon I_Connect_me_62x31;
 | 
			
		||||
extern const Icon I_Connected_62x31;
 | 
			
		||||
extern const Icon I_Drive_112x35;
 | 
			
		||||
extern const Icon I_Error_62x31;
 | 
			
		||||
extern const Icon I_DolphinExcited_64x63;
 | 
			
		||||
extern const Icon I_DolphinMafia_115x62;
 | 
			
		||||
extern const Icon I_DolphinNice_96x59;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/U2F/Auth_62x31.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/U2F/Auth_62x31.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.7 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/U2F/Connect_me_62x31.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/U2F/Connect_me_62x31.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.7 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/U2F/Connected_62x31.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/U2F/Connected_62x31.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.7 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/U2F/Drive_112x35.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/U2F/Drive_112x35.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/U2F/Error_62x31.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/U2F/Error_62x31.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.7 KiB  | 
@ -81,27 +81,3 @@
 | 
			
		||||
#ifndef FURI_CRITICAL_EXIT
 | 
			
		||||
#define FURI_CRITICAL_EXIT() __set_PRIMASK(primask_bit)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef FURI_CONST_ASSIGN
 | 
			
		||||
#define FURI_CONST_ASSIGN_(T, x, y) \
 | 
			
		||||
    ({                              \
 | 
			
		||||
        T* tmp_x = (T*)&x;          \
 | 
			
		||||
        *tmp_x = y;                 \
 | 
			
		||||
        *tmp_x;                     \
 | 
			
		||||
    })
 | 
			
		||||
#define FURI_CONST_ASSIGN(x, y)                                        \
 | 
			
		||||
    _Generic((x), signed char                                          \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(signed char, x, y), unsigned char    \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(unsigned char, x, y), short          \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(short, x, y), unsigned short         \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(unsigned short, x, y), int           \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(int, x, y), unsigned                 \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(unsigned, x, y), long                \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(long, x, y), unsigned long           \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(unsigned long, x, y), long long      \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(long long, x, y), unsigned long long \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(unsigned long long, x, y), float     \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(float, x, y), double                 \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(double, x, y), long double           \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(long double, x, y))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										38
									
								
								core/furi/dangerous_defines.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								core/furi/dangerous_defines.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
/** Assign value to variable with const modifier
 | 
			
		||||
 * 
 | 
			
		||||
 * This macros is equivalent to `const_cast` from C++
 | 
			
		||||
 * Literally x = y, but with some magic.
 | 
			
		||||
 * It's as dangerous as only can be.
 | 
			
		||||
 * We don't advice you to use it unless you REALLY MUST.
 | 
			
		||||
 * Like REALLY REALLY.
 | 
			
		||||
 * 
 | 
			
		||||
 * @param x - const variable 
 | 
			
		||||
 * @param y - variable
 | 
			
		||||
 * 
 | 
			
		||||
 * @return assigned variable value
 | 
			
		||||
 */
 | 
			
		||||
#ifndef FURI_CONST_ASSIGN
 | 
			
		||||
#define FURI_CONST_ASSIGN_(T, x, y) \
 | 
			
		||||
    ({                              \
 | 
			
		||||
        T* tmp_x = (T*)&x;          \
 | 
			
		||||
        *tmp_x = y;                 \
 | 
			
		||||
        *tmp_x;                     \
 | 
			
		||||
    })
 | 
			
		||||
#define FURI_CONST_ASSIGN(x, y)                                        \
 | 
			
		||||
    _Generic((x), signed char                                          \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(signed char, x, y), unsigned char    \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(unsigned char, x, y), short          \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(short, x, y), unsigned short         \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(unsigned short, x, y), int           \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(int, x, y), unsigned                 \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(unsigned, x, y), long                \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(long, x, y), unsigned long           \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(unsigned long, x, y), long long      \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(long long, x, y), unsigned long long \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(unsigned long long, x, y), float     \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(float, x, y), double                 \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(double, x, y), long double           \
 | 
			
		||||
             : FURI_CONST_ASSIGN_(long double, x, y))
 | 
			
		||||
#endif
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user