optimize totp face and add countdown
This commit is contained in:
parent
653dd862b8
commit
121e6fd165
@ -1,114 +1,58 @@
|
||||
/**
|
||||
*
|
||||
* TODO:
|
||||
* - this ONLY works if watch is set to UTC, probably worth including a TZ offset setting since it can be used by beats as well
|
||||
* - show how long code is valid for in upper right corner of LCD
|
||||
* - optimize code so that we don't calculating a new unix timestamp every second AND a new TOTP code
|
||||
* - Add support for UTC offset in settings?
|
||||
* - Support for multiple codes
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "totp_face.h"
|
||||
#include "watch.h"
|
||||
#include "watch_utility.h"
|
||||
#include "TOTP.h"
|
||||
|
||||
// test key: JBSWY3DPEHPK3PXP
|
||||
// Use https://cryptii.com/pipes/base32-to-hex to convert base32 to hex
|
||||
// Use https://totp.danhersam.com/ to generate test codes for verification
|
||||
uint8_t hmacKey[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0xde, 0xad, 0xbe, 0xef}; // Secret key
|
||||
static uint8_t hmacKey[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0xde, 0xad, 0xbe, 0xef}; // Secret key
|
||||
|
||||
|
||||
static const uint8_t UTC_OFFSET = 5; // set to your current UTC offset
|
||||
static const uint32_t TIMESTEP = 30;
|
||||
|
||||
void totp_face_setup(movement_settings_t *settings, void ** context_ptr) {
|
||||
(void) settings;
|
||||
(void) context_ptr;
|
||||
TOTP(hmacKey, sizeof(hmacKey), 30);
|
||||
if (*context_ptr == NULL) *context_ptr = malloc(sizeof(totp_state_t));
|
||||
TOTP(hmacKey, sizeof(hmacKey), TIMESTEP);
|
||||
}
|
||||
|
||||
void totp_face_activate(movement_settings_t *settings, void *context) {
|
||||
(void) settings;
|
||||
(void) context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get unix timestamp from component parts
|
||||
*
|
||||
* @param year
|
||||
* @param month
|
||||
* @param day
|
||||
* @param hour
|
||||
* @param minute
|
||||
* @param second
|
||||
* @return uint32_t
|
||||
*
|
||||
* Based on code by Josh Haberman for upb
|
||||
* from https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
|
||||
*
|
||||
* Essentially we need to calculate how many days have occured since year 0
|
||||
* including leap years! The following code does some clever calculations
|
||||
* of the number of february's then offsets based on how many leap years
|
||||
* there have been
|
||||
*
|
||||
* Once we have the number of days in the year, it's easy enough to add how
|
||||
* many days have happened in the current year, then convert that to seconds
|
||||
*/
|
||||
uint32_t current_unix_time(uint32_t year, uint32_t month, uint32_t day,
|
||||
uint32_t hour, uint32_t minute, uint32_t second) {
|
||||
uint16_t DAYS_SO_FAR[] = {
|
||||
0, // Jan
|
||||
31, // Feb
|
||||
59, // March
|
||||
90, // April
|
||||
120, // May
|
||||
151, // June
|
||||
181, // July
|
||||
212, // August
|
||||
243, // September
|
||||
273, // October
|
||||
304, // November
|
||||
334 // December
|
||||
};
|
||||
|
||||
|
||||
uint32_t year_adj = year + 4800;
|
||||
uint32_t febs = year_adj - (month <= 2 ? 1 : 0); /* Februaries since base. */
|
||||
uint32_t leap_days = 1 + (febs / 4) - (febs / 100) + (febs / 400);
|
||||
uint32_t days = 365 * year_adj + leap_days + DAYS_SO_FAR[month - 1] + day - 1;
|
||||
days -= 2472692; /* Adjust to Unix epoch. */
|
||||
|
||||
uint32_t timestamp = days * 86400;
|
||||
timestamp += hour * 3600;
|
||||
timestamp += minute * 60;
|
||||
timestamp += second;
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
uint32_t current_unix_time_from_rtc() {
|
||||
watch_date_time date_time = watch_rtc_get_date_time();
|
||||
return current_unix_time(
|
||||
date_time.unit.year + 2020, // year is stored starting in 2020
|
||||
date_time.unit.month,
|
||||
date_time.unit.day,
|
||||
date_time.unit.hour,
|
||||
date_time.unit.minute,
|
||||
date_time.unit.second
|
||||
);
|
||||
memset(context, 0, sizeof(totp_state_t));
|
||||
totp_state_t *totp_state = (totp_state_t *)context;
|
||||
totp_state->timestamp = watch_utility_date_time_to_unix_time(watch_rtc_get_date_time(), UTC_OFFSET);
|
||||
totp_state->current_code = getCodeFromTimestamp(totp_state->timestamp);
|
||||
}
|
||||
|
||||
bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
||||
(void) settings;
|
||||
(void) context;
|
||||
|
||||
totp_state_t *totp_state = (totp_state_t *)context;
|
||||
char buf[14];
|
||||
watch_date_time date_time = watch_rtc_get_date_time();
|
||||
uint8_t valid_for;
|
||||
div_t result;
|
||||
|
||||
uint32_t ts;
|
||||
uint32_t code;
|
||||
switch (event.event_type) {
|
||||
case EVENT_ACTIVATE:
|
||||
case EVENT_TICK:
|
||||
ts = current_unix_time_from_rtc();
|
||||
code = getCodeFromTimestamp(ts);
|
||||
sprintf(buf, "2f %lu", code);
|
||||
totp_state->timestamp++;
|
||||
// fall through
|
||||
case EVENT_ACTIVATE:
|
||||
result = div(totp_state->timestamp, TIMESTEP);
|
||||
if (result.quot != totp_state->steps) {
|
||||
totp_state->current_code = getCodeFromTimestamp(totp_state->timestamp);
|
||||
totp_state->steps = result.quot;
|
||||
}
|
||||
valid_for = TIMESTEP - result.rem;
|
||||
sprintf(buf, "2f%2d%lu", valid_for, totp_state->current_code);
|
||||
|
||||
watch_display_string(buf, 0);
|
||||
break;
|
||||
@ -134,4 +78,4 @@ bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void
|
||||
void totp_face_resign(movement_settings_t *settings, void *context) {
|
||||
(void) settings;
|
||||
(void) context;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,13 @@
|
||||
|
||||
#include "movement.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t timestamp;
|
||||
uint8_t steps;
|
||||
uint32_t current_code;
|
||||
|
||||
} totp_state_t;
|
||||
|
||||
void totp_face_setup(movement_settings_t *settings, void ** context_ptr);
|
||||
void totp_face_activate(movement_settings_t *settings, void *context);
|
||||
bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
||||
@ -16,4 +23,4 @@ static const watch_face_t totp_face = {
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif // TOTP_FACE_H_
|
||||
#endif // TOTP_FACE_H_
|
||||
|
Loading…
x
Reference in New Issue
Block a user