Remove MPW_COLOR from core, safer decryption, more standard password input & curses dialog.
This commit is contained in:
parent
877eba66be
commit
9443d93500
@ -262,3 +262,40 @@ const char mpw_characterFromClass(char characterClass, uint8_t seedByte) {
|
|||||||
|
|
||||||
return classCharacters[seedByte % strlen( classCharacters )];
|
return classCharacters[seedByte % strlen( classCharacters )];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MPIdenticon mpw_identicon(const char *fullName, const char *masterPassword) {
|
||||||
|
|
||||||
|
const char *leftArm[] = { "╔", "╚", "╰", "═" };
|
||||||
|
const char *rightArm[] = { "╗", "╝", "╯", "═" };
|
||||||
|
const char *body[] = { "█", "░", "▒", "▓", "☺", "☻" };
|
||||||
|
const char *accessory[] = {
|
||||||
|
"◈", "◎", "◐", "◑", "◒", "◓", "☀", "☁", "☂", "☃", "", "★", "☆", "☎", "☏", "⎈", "⌂", "☘", "☢", "☣",
|
||||||
|
"☕", "⌚", "⌛", "⏰", "⚡", "⛄", "⛅", "☔", "♔", "♕", "♖", "♗", "♘", "♙", "♚", "♛", "♜", "♝", "♞", "♟",
|
||||||
|
"♨", "♩", "♪", "♫", "⚐", "⚑", "⚔", "⚖", "⚙", "⚠", "⌘", "⏎", "✄", "✆", "✈", "✉", "✌"
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t *identiconSeed = NULL;
|
||||||
|
if (fullName && strlen( fullName ) && masterPassword && strlen( masterPassword ))
|
||||||
|
identiconSeed = mpw_hash_hmac_sha256(
|
||||||
|
(const uint8_t *)masterPassword, strlen( masterPassword ),
|
||||||
|
(const uint8_t *)fullName, strlen( fullName ) );
|
||||||
|
if (!identiconSeed)
|
||||||
|
return (MPIdenticon){
|
||||||
|
.leftArm = "",
|
||||||
|
.body = "",
|
||||||
|
.rightArm = "",
|
||||||
|
.accessory = "",
|
||||||
|
.color=0,
|
||||||
|
};
|
||||||
|
|
||||||
|
MPIdenticon identicon = {
|
||||||
|
.leftArm = leftArm[identiconSeed[0] % (sizeof( leftArm ) / sizeof( leftArm[0] ))],
|
||||||
|
.body = body[identiconSeed[1] % (sizeof( body ) / sizeof( body[0] ))],
|
||||||
|
.rightArm = rightArm[identiconSeed[2] % (sizeof( rightArm ) / sizeof( rightArm[0] ))],
|
||||||
|
.accessory = accessory[identiconSeed[3] % (sizeof( accessory ) / sizeof( accessory[0] ))],
|
||||||
|
.color = (uint8_t)(identiconSeed[4] % 7 + 1),
|
||||||
|
};
|
||||||
|
mpw_free( &identiconSeed, 32 );
|
||||||
|
|
||||||
|
return identicon;
|
||||||
|
}
|
||||||
|
@ -111,6 +111,14 @@ typedef mpw_enum ( uint32_t, MPCounterValue ) {
|
|||||||
MPCounterValueLast = UINT32_MAX,
|
MPCounterValueLast = UINT32_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *leftArm;
|
||||||
|
const char *body;
|
||||||
|
const char *rightArm;
|
||||||
|
const char *accessory;
|
||||||
|
uint8_t color;
|
||||||
|
} MPIdenticon;
|
||||||
|
|
||||||
//// Type utilities.
|
//// Type utilities.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,4 +165,7 @@ const char *mpw_charactersInClass(char characterClass);
|
|||||||
*/
|
*/
|
||||||
const char mpw_characterFromClass(char characterClass, uint8_t seedByte);
|
const char mpw_characterFromClass(char characterClass, uint8_t seedByte);
|
||||||
|
|
||||||
|
/** @return A fingerprint for a user. */
|
||||||
|
MPIdenticon mpw_identicon(const char *fullName, const char *masterPassword);
|
||||||
|
|
||||||
#endif // _MPW_TYPES_H
|
#endif // _MPW_TYPES_H
|
||||||
|
@ -20,12 +20,6 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#if MPW_COLOR
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <curses.h>
|
|
||||||
#include <term.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MPW_CPERCIVA
|
#if MPW_CPERCIVA
|
||||||
#include <scrypt/crypto_scrypt.h>
|
#include <scrypt/crypto_scrypt.h>
|
||||||
#include <scrypt/sha256.h>
|
#include <scrypt/sha256.h>
|
||||||
@ -274,9 +268,10 @@ uint8_t const *mpw_hash_hmac_sha256(const uint8_t *key, const size_t keySize, co
|
|||||||
return mac;
|
return mac;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We do our best to not fail on odd buf's, eg. non-padded cipher texts.
|
||||||
static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t keySize, const uint8_t *buf, size_t *bufSize) {
|
static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t keySize, const uint8_t *buf, size_t *bufSize) {
|
||||||
|
|
||||||
if (!key || keySize < 16)
|
if (!key || keySize < 16 || !*bufSize)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// IV = zero
|
// IV = zero
|
||||||
@ -284,9 +279,9 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
|
|||||||
mpw_zero( iv, sizeof iv );
|
mpw_zero( iv, sizeof iv );
|
||||||
|
|
||||||
// Add PKCS#7 padding
|
// Add PKCS#7 padding
|
||||||
uint32_t aesSize = (uint32_t)*bufSize;
|
uint32_t aesSize = ((uint32_t)*bufSize + 15 / 16) * 16; // round up to block size.
|
||||||
if (encrypt)
|
if (encrypt && !(*bufSize % 16)) // add pad block if plain text fits block size.
|
||||||
aesSize = (aesSize / 16) * 16 + 16;
|
encrypt += 16;
|
||||||
uint8_t aesBuf[aesSize];
|
uint8_t aesBuf[aesSize];
|
||||||
memcpy( aesBuf, buf, *bufSize );
|
memcpy( aesBuf, buf, *bufSize );
|
||||||
memset( aesBuf + *bufSize, aesSize - *bufSize, aesSize - *bufSize );
|
memset( aesBuf + *bufSize, aesSize - *bufSize, aesSize - *bufSize );
|
||||||
@ -302,7 +297,7 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
|
|||||||
// Truncate PKCS#7 padding
|
// Truncate PKCS#7 padding
|
||||||
if (encrypt)
|
if (encrypt)
|
||||||
*bufSize = aesSize;
|
*bufSize = aesSize;
|
||||||
else
|
else if (*bufSize % 16 == 0 && resultBuf[aesSize - 1] < 16)
|
||||||
*bufSize -= resultBuf[aesSize - 1];
|
*bufSize -= resultBuf[aesSize - 1];
|
||||||
|
|
||||||
return resultBuf;
|
return resultBuf;
|
||||||
@ -443,99 +438,6 @@ const char *mpw_hex_l(uint32_t number) {
|
|||||||
return mpw_hex( &buf, sizeof( buf ) );
|
return mpw_hex( &buf, sizeof( buf ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MPW_COLOR
|
|
||||||
static char *str_tputs;
|
|
||||||
static int str_tputs_cursor;
|
|
||||||
static const int str_tputs_max = 256;
|
|
||||||
|
|
||||||
static bool mpw_setupterm() {
|
|
||||||
|
|
||||||
if (!isatty( STDERR_FILENO ))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
static bool termsetup;
|
|
||||||
if (!termsetup) {
|
|
||||||
int errret;
|
|
||||||
if (!(termsetup = (setupterm( NULL, STDERR_FILENO, &errret ) == OK))) {
|
|
||||||
wrn( "Terminal doesn't support color (setupterm errret %d).\n", errret );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mpw_tputc(int c) {
|
|
||||||
|
|
||||||
if (++str_tputs_cursor < str_tputs_max) {
|
|
||||||
str_tputs[str_tputs_cursor] = (char)c;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *mpw_tputs(const char *str, int affcnt) {
|
|
||||||
|
|
||||||
if (str_tputs)
|
|
||||||
mpw_free( &str_tputs, str_tputs_max );
|
|
||||||
str_tputs = calloc( str_tputs_max, sizeof( char ) );
|
|
||||||
str_tputs_cursor = -1;
|
|
||||||
|
|
||||||
char *result = tputs( str, affcnt, mpw_tputc ) == ERR? NULL: mpw_strndup( str_tputs, str_tputs_max );
|
|
||||||
if (str_tputs)
|
|
||||||
mpw_free( &str_tputs, str_tputs_max );
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char *mpw_identicon(const char *fullName, const char *masterPassword) {
|
|
||||||
|
|
||||||
const char *leftArm[] = { "╔", "╚", "╰", "═" };
|
|
||||||
const char *rightArm[] = { "╗", "╝", "╯", "═" };
|
|
||||||
const char *body[] = { "█", "░", "▒", "▓", "☺", "☻" };
|
|
||||||
const char *accessory[] = {
|
|
||||||
"◈", "◎", "◐", "◑", "◒", "◓", "☀", "☁", "☂", "☃", "☄", "★", "☆", "☎", "☏", "⎈", "⌂", "☘", "☢", "☣",
|
|
||||||
"☕", "⌚", "⌛", "⏰", "⚡", "⛄", "⛅", "☔", "♔", "♕", "♖", "♗", "♘", "♙", "♚", "♛", "♜", "♝", "♞", "♟",
|
|
||||||
"♨", "♩", "♪", "♫", "⚐", "⚑", "⚔", "⚖", "⚙", "⚠", "⌘", "⏎", "✄", "✆", "✈", "✉", "✌"
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t *identiconSeed = mpw_hash_hmac_sha256(
|
|
||||||
(const uint8_t *)masterPassword, strlen( masterPassword ),
|
|
||||||
(const uint8_t *)fullName, strlen( fullName ) );
|
|
||||||
if (!identiconSeed)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
char *colorString, *resetString;
|
|
||||||
#ifdef MPW_COLOR
|
|
||||||
if (mpw_setupterm()) {
|
|
||||||
uint8_t colorIdentifier = (uint8_t)(identiconSeed[4] % 7 + 1);
|
|
||||||
colorString = mpw_tputs( tparm( tgetstr( "AF", NULL ), colorIdentifier ), 1 );
|
|
||||||
resetString = mpw_tputs( tgetstr( "me", NULL ), 1 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
colorString = calloc( 1, sizeof( char ) );
|
|
||||||
resetString = calloc( 1, sizeof( char ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
char *identicon = (char *)calloc( 256, sizeof( char ) );
|
|
||||||
snprintf( identicon, 256, "%s%s%s%s%s%s",
|
|
||||||
colorString,
|
|
||||||
leftArm[identiconSeed[0] % (sizeof( leftArm ) / sizeof( leftArm[0] ))],
|
|
||||||
body[identiconSeed[1] % (sizeof( body ) / sizeof( body[0] ))],
|
|
||||||
rightArm[identiconSeed[2] % (sizeof( rightArm ) / sizeof( rightArm[0] ))],
|
|
||||||
accessory[identiconSeed[3] % (sizeof( accessory ) / sizeof( accessory[0] ))],
|
|
||||||
resetString );
|
|
||||||
|
|
||||||
mpw_free( &identiconSeed, 32 );
|
|
||||||
mpw_free_strings( &colorString, &resetString, NULL );
|
|
||||||
return identicon;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the amount of bytes used by UTF-8 to encode a single character that starts with the given byte.
|
* @return the amount of bytes used by UTF-8 to encode a single character that starts with the given byte.
|
||||||
*/
|
*/
|
||||||
@ -568,6 +470,10 @@ const size_t mpw_utf8_strlen(const char *utf8String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *mpw_strdup(const char *src) {
|
char *mpw_strdup(const char *src) {
|
||||||
|
|
||||||
|
if (!src)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
size_t len = strlen( src );
|
size_t len = strlen( src );
|
||||||
char *dst = malloc( len + 1 );
|
char *dst = malloc( len + 1 );
|
||||||
memcpy( dst, src, len );
|
memcpy( dst, src, len );
|
||||||
@ -577,6 +483,10 @@ char *mpw_strdup(const char *src) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *mpw_strndup(const char *src, size_t max) {
|
char *mpw_strndup(const char *src, size_t max) {
|
||||||
|
|
||||||
|
if (!src)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
for (; len < max && src[len] != '\0'; ++len);
|
for (; len < max && src[len] != '\0'; ++len);
|
||||||
|
|
||||||
|
@ -203,17 +203,14 @@ MPKeyID mpw_id_buf(const void *buf, size_t length);
|
|||||||
/** Compare two fingerprints for equality.
|
/** Compare two fingerprints for equality.
|
||||||
* @return true if the buffers represent identical fingerprints. */
|
* @return true if the buffers represent identical fingerprints. */
|
||||||
bool mpw_id_buf_equals(const char *id1, const char *id2);
|
bool mpw_id_buf_equals(const char *id1, const char *id2);
|
||||||
/** Encode a visual fingerprint for a user.
|
|
||||||
* @return A newly allocated string. */
|
|
||||||
const char *mpw_identicon(const char *fullName, const char *masterPassword);
|
|
||||||
|
|
||||||
//// String utilities.
|
//// String utilities.
|
||||||
|
|
||||||
/** @return The amount of display characters in the given UTF-8 string. */
|
/** @return The amount of display characters in the given UTF-8 string. */
|
||||||
const size_t mpw_utf8_strlen(const char *utf8String);
|
const size_t mpw_utf8_strlen(const char *utf8String);
|
||||||
/** Drop-in for non-standard strdup(3). */
|
/** Drop-in for POSIX strdup(3). */
|
||||||
char *mpw_strdup(const char *src);
|
char *mpw_strdup(const char *src);
|
||||||
/** Drop-in for non-standard strndup(3). */
|
/** Drop-in for POSIX strndup(3). */
|
||||||
char *mpw_strndup(const char *src, size_t max);
|
char *mpw_strndup(const char *src, size_t max);
|
||||||
|
|
||||||
#endif // _MPW_UTIL_H
|
#endif // _MPW_UTIL_H
|
||||||
|
@ -28,18 +28,21 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sysexits.h>
|
#include <sysexits.h>
|
||||||
|
|
||||||
|
#define MPW_MAX_INPUT 60
|
||||||
|
|
||||||
|
#if MPW_COLOR
|
||||||
|
#include <curses.h>
|
||||||
|
#include <term.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "mpw-util.h"
|
#include "mpw-util.h"
|
||||||
|
|
||||||
/** Read the value of an environment variable.
|
|
||||||
* @return A newly allocated string or NULL if the variable doesn't exist. */
|
|
||||||
const char *mpw_getenv(const char *variableName) {
|
const char *mpw_getenv(const char *variableName) {
|
||||||
|
|
||||||
char *envBuf = getenv( variableName );
|
char *envBuf = getenv( variableName );
|
||||||
return envBuf? mpw_strdup( envBuf ): NULL;
|
return envBuf? mpw_strdup( envBuf ): NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Use the askpass program to prompt the user.
|
|
||||||
* @return A newly allocated string or NULL if askpass is not supported or an error occurred. */
|
|
||||||
char *mpw_askpass(const char *prompt) {
|
char *mpw_askpass(const char *prompt) {
|
||||||
|
|
||||||
const char *askpass = mpw_getenv( MP_ENV_askpass );
|
const char *askpass = mpw_getenv( MP_ENV_askpass );
|
||||||
@ -91,15 +94,59 @@ char *mpw_askpass(const char *prompt) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ask the user a question.
|
static const char *_mpw_getline(const char *prompt, bool silent) {
|
||||||
* @return A newly allocated string or NULL if an error occurred trying to read from the user. */
|
|
||||||
const char *mpw_getline(const char *prompt) {
|
|
||||||
|
|
||||||
// Get answer from askpass.
|
// Get answer from askpass.
|
||||||
char *answer = mpw_askpass( prompt );
|
char *answer = mpw_askpass( prompt );
|
||||||
if (answer)
|
if (answer)
|
||||||
return answer;
|
return answer;
|
||||||
|
|
||||||
|
#if MPW_COLOR
|
||||||
|
// Initialize a curses screen.
|
||||||
|
initscr();
|
||||||
|
start_color();
|
||||||
|
init_pair( 1, COLOR_WHITE, COLOR_BLUE );
|
||||||
|
init_pair( 2, COLOR_BLACK, COLOR_WHITE );
|
||||||
|
int rows, cols;
|
||||||
|
getmaxyx( stdscr, rows, cols );
|
||||||
|
|
||||||
|
// Display a dialog box.
|
||||||
|
int width = max( prompt? (int)strlen( prompt ): 0, MPW_MAX_INPUT ) + 6;
|
||||||
|
char *version = "mpw v" stringify_def( MP_VERSION );
|
||||||
|
mvprintw( rows - 1, (cols - (int)strlen( version )) / 2, "%s", version );
|
||||||
|
attron( A_BOLD );
|
||||||
|
color_set( 2, NULL );
|
||||||
|
mvprintw( rows / 2 - 1, (cols - width) / 2, "%s%*s%s", "*", width - 2, "", "*" );
|
||||||
|
mvprintw( rows / 2 - 1, (cols - (int)strlen( prompt )) / 2, "%s", prompt );
|
||||||
|
color_set( 1, NULL );
|
||||||
|
mvprintw( rows / 2 + 0, (cols - width) / 2, "%s%*s%s", "|", width - 2, "", "|" );
|
||||||
|
mvprintw( rows / 2 + 1, (cols - width) / 2, "%s%*s%s", "|", width - 2, "", "|" );
|
||||||
|
mvprintw( rows / 2 + 2, (cols - width) / 2, "%s%*s%s", "|", width - 2, "", "|" );
|
||||||
|
|
||||||
|
// Read response.
|
||||||
|
color_set( 2, NULL );
|
||||||
|
attron( A_STANDOUT );
|
||||||
|
int result = ERR;
|
||||||
|
char str[MPW_MAX_INPUT + 1];
|
||||||
|
if (silent) {
|
||||||
|
mvprintw( rows / 2 + 1, (cols - 5) / 2, "[ * ]" );
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
noecho();
|
||||||
|
result = mvgetnstr( rows / 2 + 1, (cols - 1) / 2, str, MPW_MAX_INPUT );
|
||||||
|
echo();
|
||||||
|
} else {
|
||||||
|
mvprintw( rows / 2 + 1, (cols - (MPW_MAX_INPUT + 2)) / 2, "%*s", MPW_MAX_INPUT + 2, "" );
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
echo();
|
||||||
|
result = mvgetnstr( rows / 2 + 1, (cols - MPW_MAX_INPUT) / 2, str, MPW_MAX_INPUT );
|
||||||
|
}
|
||||||
|
attrset( 0 );
|
||||||
|
endwin();
|
||||||
|
|
||||||
|
return result == ERR? NULL: mpw_strndup( str, MPW_MAX_INPUT );
|
||||||
|
#else
|
||||||
// Get password from terminal.
|
// Get password from terminal.
|
||||||
fprintf( stderr, "%s ", prompt );
|
fprintf( stderr, "%s ", prompt );
|
||||||
|
|
||||||
@ -113,31 +160,19 @@ const char *mpw_getline(const char *prompt) {
|
|||||||
// Remove trailing newline.
|
// Remove trailing newline.
|
||||||
answer[lineSize - 1] = '\0';
|
answer[lineSize - 1] = '\0';
|
||||||
return answer;
|
return answer;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *mpw_getline(const char *prompt) {
|
||||||
|
|
||||||
|
return _mpw_getline( prompt, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ask the user for a password.
|
|
||||||
* @return A newly allocated string or NULL if an error occurred trying to read from the user. */
|
|
||||||
const char *mpw_getpass(const char *prompt) {
|
const char *mpw_getpass(const char *prompt) {
|
||||||
|
|
||||||
// Get password from askpass.
|
return _mpw_getline( prompt, true );
|
||||||
const char *password = mpw_askpass( prompt );
|
|
||||||
if (password)
|
|
||||||
return password;
|
|
||||||
|
|
||||||
// Get password from terminal.
|
|
||||||
char *answer = getpass( prompt );
|
|
||||||
if (!answer)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
password = mpw_strdup( answer );
|
|
||||||
mpw_zero( answer, strlen( answer ) );
|
|
||||||
return password;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the absolute path to the mpw configuration file with the given prefix name and file extension.
|
|
||||||
* Resolves the file <prefix.extension> as located in the <.mpw.d> directory inside the user's home directory
|
|
||||||
* or current directory if it couldn't be resolved.
|
|
||||||
* @return A newly allocated string. */
|
|
||||||
const char *mpw_path(const char *prefix, const char *extension) {
|
const char *mpw_path(const char *prefix, const char *extension) {
|
||||||
|
|
||||||
// Resolve user's home directory.
|
// Resolve user's home directory.
|
||||||
@ -180,8 +215,6 @@ const char *mpw_path(const char *prefix, const char *extension) {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** mkdir all the directories up to the directory of the given file path.
|
|
||||||
* @return true if the file's path exists. */
|
|
||||||
bool mpw_mkdirs(const char *filePath) {
|
bool mpw_mkdirs(const char *filePath) {
|
||||||
|
|
||||||
if (!filePath)
|
if (!filePath)
|
||||||
@ -215,8 +248,6 @@ bool mpw_mkdirs(const char *filePath) {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Read until EOF from the given file descriptor.
|
|
||||||
* @return A newly allocated string or NULL if the read buffer couldn't be allocated or an error occurred. */
|
|
||||||
char *mpw_read_fd(int fd) {
|
char *mpw_read_fd(int fd) {
|
||||||
|
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
@ -230,8 +261,6 @@ char *mpw_read_fd(int fd) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Read the file contents of a given file.
|
|
||||||
* @return A newly allocated string or NULL if the read buffer couldn't be allocated. */
|
|
||||||
char *mpw_read_file(FILE *file) {
|
char *mpw_read_file(FILE *file) {
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
@ -245,3 +274,73 @@ char *mpw_read_file(FILE *file) {
|
|||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MPW_COLOR
|
||||||
|
static char *str_tputs;
|
||||||
|
static int str_tputs_cursor;
|
||||||
|
static const int str_tputs_max = 256;
|
||||||
|
|
||||||
|
static bool mpw_setupterm() {
|
||||||
|
|
||||||
|
if (!isatty( STDERR_FILENO ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
static bool termsetup;
|
||||||
|
if (!termsetup) {
|
||||||
|
int errret;
|
||||||
|
if (!(termsetup = (setupterm( NULL, STDERR_FILENO, &errret ) == OK))) {
|
||||||
|
wrn( "Terminal doesn't support color (setupterm errret %d).\n", errret );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mpw_tputc(int c) {
|
||||||
|
|
||||||
|
if (++str_tputs_cursor < str_tputs_max) {
|
||||||
|
str_tputs[str_tputs_cursor] = (char)c;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *mpw_tputs(const char *str, int affcnt) {
|
||||||
|
|
||||||
|
if (str_tputs)
|
||||||
|
mpw_free( &str_tputs, str_tputs_max );
|
||||||
|
str_tputs = calloc( str_tputs_max, sizeof( char ) );
|
||||||
|
str_tputs_cursor = -1;
|
||||||
|
|
||||||
|
char *result = tputs( str, affcnt, mpw_tputc ) == ERR? NULL: mpw_strndup( str_tputs, str_tputs_max );
|
||||||
|
if (str_tputs)
|
||||||
|
mpw_free( &str_tputs, str_tputs_max );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *mpw_identicon_str(MPIdenticon identicon) {
|
||||||
|
|
||||||
|
char *colorString, *resetString;
|
||||||
|
#ifdef MPW_COLOR
|
||||||
|
if (mpw_setupterm()) {
|
||||||
|
colorString = mpw_tputs( tparm( tgetstr( "AF", NULL ), identicon.color ), 1 );
|
||||||
|
resetString = mpw_tputs( tgetstr( "me", NULL ), 1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
colorString = calloc( 1, sizeof( char ) );
|
||||||
|
resetString = calloc( 1, sizeof( char ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *str = mpw_str( "%s%s%s%s%s%s",
|
||||||
|
colorString, identicon.leftArm, identicon.body, identicon.rightArm, identicon.accessory, resetString );
|
||||||
|
mpw_free_strings( &colorString, &resetString, NULL );
|
||||||
|
|
||||||
|
return mpw_strdup( str );
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "mpw-types.h"
|
||||||
|
|
||||||
#ifndef MP_VERSION
|
#ifndef MP_VERSION
|
||||||
#define MP_VERSION ?
|
#define MP_VERSION ?
|
||||||
@ -62,3 +63,7 @@ char *mpw_read_fd(int fd);
|
|||||||
/** Read the file contents of a given file.
|
/** Read the file contents of a given file.
|
||||||
* @return A newly allocated string or NULL the read buffer couldn't be allocated. */
|
* @return A newly allocated string or NULL the read buffer couldn't be allocated. */
|
||||||
char *mpw_read_file(FILE *file);
|
char *mpw_read_file(FILE *file);
|
||||||
|
|
||||||
|
/** Encode a visual fingerprint for a user.
|
||||||
|
* @return A newly allocated string. */
|
||||||
|
const char *mpw_identicon_str(MPIdenticon identicon);
|
||||||
|
@ -564,7 +564,7 @@ void cli_question(Arguments __unused *args, Operation *operation) {
|
|||||||
|
|
||||||
void cli_operation(Arguments __unused *args, Operation *operation) {
|
void cli_operation(Arguments __unused *args, Operation *operation) {
|
||||||
|
|
||||||
operation->identicon = mpw_identicon( operation->user->fullName, operation->user->masterPassword );
|
operation->identicon = mpw_identicon_str( mpw_identicon( operation->user->fullName, operation->user->masterPassword ) );
|
||||||
|
|
||||||
if (!operation->site)
|
if (!operation->site)
|
||||||
abort();
|
abort();
|
||||||
|
Loading…
Reference in New Issue
Block a user