Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8043ae16d | ||
|
|
7150f2f5c5 | ||
|
|
81bd2e3065 | ||
|
|
78c9618807 | ||
|
|
bed8939b8a | ||
|
|
9443d93500 | ||
|
|
877eba66be | ||
|
|
3af8aba40c | ||
|
|
7ece02c73d | ||
|
|
ebbd2b3ac4 |
@@ -176,7 +176,7 @@ static const char *mpw_sitePasswordFromCrypt_v0(
|
||||
// Decrypt
|
||||
const uint8_t *plainBytes = mpw_aes_decrypt( masterKey, MPMasterKeySize, cipherBuf, &bufSize );
|
||||
mpw_free( &cipherBuf, cipherBufSize );
|
||||
const char *plainText = strndup( (char *)plainBytes, bufSize );
|
||||
const char *plainText = mpw_strndup( (char *)plainBytes, bufSize );
|
||||
mpw_free( &plainBytes, bufSize );
|
||||
if (!plainText)
|
||||
err( "AES decryption error: %s\n", strerror( errno ) );
|
||||
|
||||
@@ -28,7 +28,7 @@ char *mpw_get_token(const char **in, const char *eol, char *delim) {
|
||||
|
||||
// Find characters up to the first delim.
|
||||
size_t len = strcspn( *in, delim );
|
||||
char *token = len && len <= (size_t)(eol - *in)? strndup( *in, len ): NULL;
|
||||
char *token = len && len <= (size_t)(eol - *in)? mpw_strndup( *in, len ): NULL;
|
||||
|
||||
// Advance past the delimitor.
|
||||
*in = min( eol, *in + len + 1 );
|
||||
@@ -38,30 +38,12 @@ char *mpw_get_token(const char **in, const char *eol, char *delim) {
|
||||
time_t mpw_mktime(
|
||||
const char *time) {
|
||||
|
||||
struct tm tm = { .tm_isdst = -1, .tm_gmtoff = 0 };
|
||||
struct tm tm = { .tm_isdst = -1 };
|
||||
if (time && sscanf( time, "%4d-%2d-%2dT%2d:%2d:%2dZ",
|
||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec ) == 6) {
|
||||
tm.tm_year -= 1900; // tm_year 0 = rfc3339 year 1900
|
||||
tm.tm_mon -= 1; // tm_mon 0 = rfc3339 month 1
|
||||
/*
|
||||
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_ARITHMETIC (code=EXC_I386_DIV, subcode=0x0)
|
||||
frame #0: 0x00007fff9fe4d219 libsystem_notify.dylib`_nc_table_find_64 + 22
|
||||
libsystem_notify.dylib`_nc_table_find_64:
|
||||
-> 0x7fff9fe4d219 <+22>: divl 0x4(%rdi)
|
||||
0x7fff9fe4d21c <+25>: movq 0x8(%rdi), %rax
|
||||
0x7fff9fe4d220 <+29>: movq (%rax,%rdx,8), %rcx
|
||||
0x7fff9fe4d224 <+33>: xorl %eax, %eax
|
||||
(lldb) bt
|
||||
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_ARITHMETIC (code=EXC_I386_DIV, subcode=0x0)
|
||||
* frame #0: 0x00007fff9fe4d219 libsystem_notify.dylib`_nc_table_find_64 + 22
|
||||
frame #1: 0x00007fff9fe4a21e libsystem_notify.dylib`registration_node_find + 53
|
||||
frame #2: 0x00007fff9fe4b78d libsystem_notify.dylib`notify_check + 105
|
||||
frame #3: 0x00007fff9fccc164 libsystem_c.dylib`notify_check_tz + 24
|
||||
frame #4: 0x00007fff9fccbd97 libsystem_c.dylib`tzsetwall_basic + 45
|
||||
frame #5: 0x00007fff9fccdcd0 libsystem_c.dylib`mktime + 46
|
||||
frame #6: 0x0000000100009496 mpw`mpw_mktime(time="2017-04-16T03:16:35Z") at mpw-marshal-util.c:47
|
||||
*/
|
||||
return mktime( &tm );
|
||||
}
|
||||
|
||||
@@ -73,7 +55,7 @@ json_object *mpw_get_json_section(
|
||||
json_object *obj, const char *section) {
|
||||
|
||||
json_object *json_value = obj;
|
||||
char *sectionTokenizer = strdup( section ), *sectionToken = sectionTokenizer;
|
||||
char *sectionTokenizer = mpw_strdup( section ), *sectionToken = sectionTokenizer;
|
||||
for (sectionToken = strtok( sectionToken, "." ); sectionToken; sectionToken = strtok( NULL, "." ))
|
||||
if (!json_object_object_get_ex( json_value, sectionToken, &json_value ) || !json_value) {
|
||||
trc( "While resolving: %s: Missing value for: %s\n", section, sectionToken );
|
||||
|
||||
@@ -33,8 +33,8 @@ MPMarshalledUser *mpw_marshal_user(
|
||||
return NULL;
|
||||
|
||||
*user = (MPMarshalledUser){
|
||||
.fullName = strdup( fullName ),
|
||||
.masterPassword = strdup( masterPassword ),
|
||||
.fullName = mpw_strdup( fullName ),
|
||||
.masterPassword = mpw_strdup( masterPassword ),
|
||||
.algorithm = algorithmVersion,
|
||||
.redacted = true,
|
||||
|
||||
@@ -46,7 +46,7 @@ MPMarshalledUser *mpw_marshal_user(
|
||||
.sites = NULL,
|
||||
};
|
||||
return user;
|
||||
};
|
||||
}
|
||||
|
||||
MPMarshalledSite *mpw_marshal_site(
|
||||
MPMarshalledUser *user, const char *siteName, const MPResultType resultType,
|
||||
@@ -57,7 +57,7 @@ MPMarshalledSite *mpw_marshal_site(
|
||||
|
||||
MPMarshalledSite *site = &user->sites[user->sites_count - 1];
|
||||
*site = (MPMarshalledSite){
|
||||
.name = strdup( siteName ),
|
||||
.name = mpw_strdup( siteName ),
|
||||
.content = NULL,
|
||||
.type = resultType,
|
||||
.counter = siteCounter,
|
||||
@@ -74,7 +74,7 @@ MPMarshalledSite *mpw_marshal_site(
|
||||
.questions = NULL,
|
||||
};
|
||||
return site;
|
||||
};
|
||||
}
|
||||
|
||||
MPMarshalledQuestion *mpw_marshal_question(
|
||||
MPMarshalledSite *site, const char *keyword) {
|
||||
@@ -86,7 +86,7 @@ MPMarshalledQuestion *mpw_marshal_question(
|
||||
|
||||
MPMarshalledQuestion *question = &site->questions[site->questions_count - 1];
|
||||
*question = (MPMarshalledQuestion){
|
||||
.keyword = strdup( keyword ),
|
||||
.keyword = mpw_strdup( keyword ),
|
||||
.content = NULL,
|
||||
.type = MPResultTypeTemplatePhrase,
|
||||
};
|
||||
@@ -198,9 +198,9 @@ static bool mpw_marshal_write_flat(
|
||||
else {
|
||||
// Redacted
|
||||
if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
|
||||
content = strdup( site->content );
|
||||
content = mpw_strdup( site->content );
|
||||
if (site->loginType & MPSiteFeatureExportContent && site->loginContent && strlen( site->loginContent ))
|
||||
loginContent = strdup( site->loginContent );
|
||||
loginContent = mpw_strdup( site->loginContent );
|
||||
}
|
||||
|
||||
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
|
||||
@@ -284,9 +284,9 @@ static bool mpw_marshal_write_json(
|
||||
else {
|
||||
// Redacted
|
||||
if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
|
||||
content = strdup( site->content );
|
||||
content = mpw_strdup( site->content );
|
||||
if (site->loginType & MPSiteFeatureExportContent && site->loginContent && strlen( site->loginContent ))
|
||||
loginContent = strdup( site->loginContent );
|
||||
loginContent = mpw_strdup( site->loginContent );
|
||||
}
|
||||
|
||||
json_object *json_site = json_object_new_object();
|
||||
@@ -397,9 +397,9 @@ static void mpw_marshal_read_flat_info(
|
||||
if (strcmp( headerName, "Algorithm" ) == 0)
|
||||
info->algorithm = (MPAlgorithmVersion)atoi( headerValue );
|
||||
if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0)
|
||||
info->fullName = strdup( headerValue );
|
||||
info->fullName = mpw_strdup( headerValue );
|
||||
if (strcmp( headerName, "Key ID" ) == 0)
|
||||
info->keyID = strdup( headerValue );
|
||||
info->keyID = mpw_strdup( headerValue );
|
||||
if (strcmp( headerName, "Passwords" ) == 0)
|
||||
info->redacted = strcmp( headerValue, "VISIBLE" ) != 0;
|
||||
if (strcmp( headerName, "Date" ) == 0)
|
||||
@@ -456,18 +456,18 @@ static MPMarshalledUser *mpw_marshal_read_flat(
|
||||
char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" );
|
||||
if (!headerName || !headerValue) {
|
||||
error->type = MPMarshalErrorStructure;
|
||||
error->description = mpw_str( "Invalid header: %s", strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) );
|
||||
error->description = mpw_str( "Invalid header: %s", mpw_strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp( headerName, "Format" ) == 0)
|
||||
format = (unsigned int)atoi( headerValue );
|
||||
if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0)
|
||||
fullName = strdup( headerValue );
|
||||
fullName = mpw_strdup( headerValue );
|
||||
if (strcmp( headerName, "Avatar" ) == 0)
|
||||
avatar = (unsigned int)atoi( headerValue );
|
||||
if (strcmp( headerName, "Key ID" ) == 0)
|
||||
keyID = strdup( headerValue );
|
||||
keyID = mpw_strdup( headerValue );
|
||||
if (strcmp( headerName, "Algorithm" ) == 0) {
|
||||
int value = atoi( headerValue );
|
||||
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
||||
@@ -527,11 +527,11 @@ static MPMarshalledUser *mpw_marshal_read_flat(
|
||||
str_uses = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
||||
char *typeAndVersion = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
||||
if (typeAndVersion) {
|
||||
str_type = strdup( strtok( typeAndVersion, ":" ) );
|
||||
str_algorithm = strdup( strtok( NULL, "" ) );
|
||||
str_type = mpw_strdup( strtok( typeAndVersion, ":" ) );
|
||||
str_algorithm = mpw_strdup( strtok( NULL, "" ) );
|
||||
mpw_free_string( &typeAndVersion );
|
||||
}
|
||||
str_counter = strdup( "1" );
|
||||
str_counter = mpw_strdup( "1" );
|
||||
siteLoginName = NULL;
|
||||
siteName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
||||
siteContent = mpw_get_token( &positionInLine, endOfLine, "\n" );
|
||||
@@ -542,9 +542,9 @@ static MPMarshalledUser *mpw_marshal_read_flat(
|
||||
str_uses = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
||||
char *typeAndVersionAndCounter = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
||||
if (typeAndVersionAndCounter) {
|
||||
str_type = strdup( strtok( typeAndVersionAndCounter, ":" ) );
|
||||
str_algorithm = strdup( strtok( NULL, ":" ) );
|
||||
str_counter = strdup( strtok( NULL, "" ) );
|
||||
str_type = mpw_strdup( strtok( typeAndVersionAndCounter, ":" ) );
|
||||
str_algorithm = mpw_strdup( strtok( NULL, ":" ) );
|
||||
str_counter = mpw_strdup( strtok( NULL, "" ) );
|
||||
mpw_free_string( &typeAndVersionAndCounter );
|
||||
}
|
||||
siteLoginName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
||||
@@ -608,9 +608,9 @@ static MPMarshalledUser *mpw_marshal_read_flat(
|
||||
else {
|
||||
// Redacted
|
||||
if (siteContent && strlen( siteContent ))
|
||||
site->content = strdup( siteContent );
|
||||
site->content = mpw_strdup( siteContent );
|
||||
if (siteLoginName && strlen( siteLoginName ))
|
||||
site->loginContent = strdup( siteLoginName );
|
||||
site->loginContent = mpw_strdup( siteLoginName );
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -650,8 +650,8 @@ static void mpw_marshal_read_json_info(
|
||||
|
||||
// Section: "user"
|
||||
info->algorithm = (MPAlgorithmVersion)mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent );
|
||||
info->fullName = strdup( mpw_get_json_string( json_file, "user.full_name", NULL ) );
|
||||
info->keyID = strdup( mpw_get_json_string( json_file, "user.key_id", NULL ) );
|
||||
info->fullName = mpw_strdup( mpw_get_json_string( json_file, "user.full_name", NULL ) );
|
||||
info->keyID = mpw_strdup( mpw_get_json_string( json_file, "user.key_id", NULL ) );
|
||||
|
||||
json_object_put( json_file );
|
||||
}
|
||||
@@ -772,7 +772,7 @@ static MPMarshalledUser *mpw_marshal_read_json(
|
||||
}
|
||||
|
||||
site->loginType = siteLoginType;
|
||||
site->url = siteURL? strdup( siteURL ): NULL;
|
||||
site->url = siteURL? mpw_strdup( siteURL ): NULL;
|
||||
site->uses = siteUses;
|
||||
site->lastUsed = siteLastUsed;
|
||||
if (!user->redacted) {
|
||||
@@ -792,9 +792,9 @@ static MPMarshalledUser *mpw_marshal_read_json(
|
||||
else {
|
||||
// Redacted
|
||||
if (siteContent && strlen( siteContent ))
|
||||
site->content = strdup( siteContent );
|
||||
site->content = mpw_strdup( siteContent );
|
||||
if (siteLoginName && strlen( siteLoginName ))
|
||||
site->loginContent = strdup( siteLoginName );
|
||||
site->loginContent = mpw_strdup( siteLoginName );
|
||||
}
|
||||
|
||||
json_object_iter json_site_question;
|
||||
@@ -813,7 +813,7 @@ static MPMarshalledUser *mpw_marshal_read_json(
|
||||
else {
|
||||
// Redacted
|
||||
if (answerContent && strlen( answerContent ))
|
||||
question->content = strdup( answerContent );
|
||||
question->content = mpw_strdup( answerContent );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,3 +262,40 @@ const char mpw_characterFromClass(char characterClass, uint8_t seedByte) {
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char *leftArm;
|
||||
const char *body;
|
||||
const char *rightArm;
|
||||
const char *accessory;
|
||||
uint8_t color;
|
||||
} MPIdenticon;
|
||||
|
||||
//// Type utilities.
|
||||
|
||||
/**
|
||||
@@ -157,4 +165,7 @@ const char *mpw_charactersInClass(char characterClass);
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -20,12 +20,6 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if MPW_COLOR
|
||||
#include <unistd.h>
|
||||
#include <curses.h>
|
||||
#include <term.h>
|
||||
#endif
|
||||
|
||||
#if MPW_CPERCIVA
|
||||
#include <scrypt/crypto_scrypt.h>
|
||||
#include <scrypt/sha256.h>
|
||||
@@ -141,7 +135,7 @@ void mpw_zero(void *buffer, size_t bufferSize) {
|
||||
|
||||
uint8_t *b = buffer;
|
||||
for (; bufferSize > 0; --bufferSize)
|
||||
*b++ = 0;
|
||||
*b++ = 0;
|
||||
}
|
||||
|
||||
bool __mpw_free(void **buffer, const size_t bufferSize) {
|
||||
@@ -274,9 +268,10 @@ uint8_t const *mpw_hash_hmac_sha256(const uint8_t *key, const size_t keySize, co
|
||||
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) {
|
||||
|
||||
if (!key || keySize < 16)
|
||||
if (!key || keySize < 16 || !*bufSize)
|
||||
return NULL;
|
||||
|
||||
// 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 );
|
||||
|
||||
// Add PKCS#7 padding
|
||||
uint32_t aesSize = (uint32_t)*bufSize;
|
||||
if (encrypt)
|
||||
aesSize = (aesSize / 16) * 16 + 16;
|
||||
uint32_t aesSize = ((uint32_t)*bufSize + 15 / 16) * 16; // round up to block size.
|
||||
if (encrypt && !(*bufSize % 16)) // add pad block if plain text fits block size.
|
||||
encrypt += 16;
|
||||
uint8_t aesBuf[aesSize];
|
||||
memcpy( aesBuf, buf, *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
|
||||
if (encrypt)
|
||||
*bufSize = aesSize;
|
||||
else
|
||||
else if (*bufSize % 16 == 0 && resultBuf[aesSize - 1] < 16)
|
||||
*bufSize -= resultBuf[aesSize - 1];
|
||||
|
||||
return resultBuf;
|
||||
@@ -343,7 +338,7 @@ const char *mpw_hotp(const uint8_t *key, size_t keySize, uint64_t movingFactor,
|
||||
|
||||
// Render the OTP as `digits` decimal digits.
|
||||
otp %= (int)pow(10, digits);
|
||||
return strdup( mpw_str( "%0*d", digits, otp ) );
|
||||
return mpw_strdup( mpw_str( "%0*d", digits, otp ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -443,99 +438,6 @@ const char *mpw_hex_l(uint32_t number) {
|
||||
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: 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.
|
||||
*/
|
||||
@@ -566,3 +468,31 @@ const size_t mpw_utf8_strlen(const char *utf8String) {
|
||||
|
||||
return charlen;
|
||||
}
|
||||
|
||||
char *mpw_strdup(const char *src) {
|
||||
|
||||
if (!src)
|
||||
return NULL;
|
||||
|
||||
size_t len = strlen( src );
|
||||
char *dst = malloc( len + 1 );
|
||||
memcpy( dst, src, len );
|
||||
dst[len] = '\0';
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *mpw_strndup(const char *src, size_t max) {
|
||||
|
||||
if (!src)
|
||||
return NULL;
|
||||
|
||||
size_t len = 0;
|
||||
for (; len < max && src[len] != '\0'; ++len);
|
||||
|
||||
char *dst = malloc( len + 1 );
|
||||
memcpy( dst, src, len );
|
||||
dst[len] = '\0';
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
@@ -203,13 +203,14 @@ MPKeyID mpw_id_buf(const void *buf, size_t length);
|
||||
/** Compare two fingerprints for equality.
|
||||
* @return true if the buffers represent identical fingerprints. */
|
||||
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.
|
||||
|
||||
/** @return The amount of display characters in the given UTF-8 string. */
|
||||
const size_t mpw_utf8_strlen(const char *utf8String);
|
||||
/** Drop-in for POSIX strdup(3). */
|
||||
char *mpw_strdup(const char *src);
|
||||
/** Drop-in for POSIX strndup(3). */
|
||||
char *mpw_strndup(const char *src, size_t max);
|
||||
|
||||
#endif // _MPW_UTIL_H
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.lyndir.masterpassword;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.util.Random;
|
||||
@@ -112,6 +113,7 @@ public class MPMasterKeyTest {
|
||||
StringBuilder password = new StringBuilder();
|
||||
for (int p = 0; p < 8; ++p)
|
||||
password.append( (char) (random.nextInt( Character.MAX_CODE_POINT - Character.MIN_CODE_POINT ) + Character.MIN_CODE_POINT) );
|
||||
logger.dbg( "password: %s", CodeUtils.encodeHex( password.toString().getBytes( Charsets.UTF_8 ) ) );
|
||||
|
||||
for (final MPMasterKey.Version version : MPMasterKey.Version.values()) {
|
||||
MPResultType resultType = MPResultType.StoredPersonal;
|
||||
@@ -119,10 +121,12 @@ public class MPMasterKeyTest {
|
||||
// Test site state
|
||||
String state = masterKey.siteState( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||
testCase.getKeyContext(), resultType, password.toString(), version );
|
||||
String result = masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||
testCase.getKeyContext(), resultType, state, version );
|
||||
logger.dbg( "result: %s", CodeUtils.encodeHex( result.getBytes( Charsets.UTF_8 ) ) );
|
||||
|
||||
assertEquals(
|
||||
masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||
testCase.getKeyContext(), resultType, state, version ),
|
||||
result,
|
||||
password.toString(),
|
||||
"[testSiteState] state mismatch: " + testCase );
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
#define _WITH_GETLINE
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include "mpw-cli-util.h"
|
||||
|
||||
#include <unistd.h>
|
||||
@@ -27,18 +28,21 @@
|
||||
#include <errno.h>
|
||||
#include <sysexits.h>
|
||||
|
||||
#define MPW_MAX_INPUT 60
|
||||
|
||||
#if MPW_COLOR
|
||||
#include <curses.h>
|
||||
#include <term.h>
|
||||
#endif
|
||||
|
||||
#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) {
|
||||
|
||||
char *envBuf = getenv( variableName );
|
||||
return envBuf? 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) {
|
||||
|
||||
const char *askpass = mpw_getenv( MP_ENV_askpass );
|
||||
@@ -90,15 +94,60 @@ char *mpw_askpass(const char *prompt) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Ask the user a question.
|
||||
* @return A newly allocated string or NULL if an error occurred trying to read from the user. */
|
||||
const char *mpw_getline(const char *prompt) {
|
||||
static const char *_mpw_getline(const char *prompt, bool silent) {
|
||||
|
||||
// Get answer from askpass.
|
||||
char *answer = mpw_askpass( prompt );
|
||||
if (answer)
|
||||
return answer;
|
||||
|
||||
#if MPW_COLOR
|
||||
// Initialize a curses screen.
|
||||
SCREEN *screen = newterm( NULL, stderr, stdin );
|
||||
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();
|
||||
delscreen( screen );
|
||||
|
||||
return result == ERR? NULL: mpw_strndup( str, MPW_MAX_INPUT );
|
||||
#else
|
||||
// Get password from terminal.
|
||||
fprintf( stderr, "%s ", prompt );
|
||||
|
||||
@@ -112,56 +161,44 @@ const char *mpw_getline(const char *prompt) {
|
||||
// Remove trailing newline.
|
||||
answer[lineSize - 1] = '\0';
|
||||
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) {
|
||||
|
||||
// Get password from askpass.
|
||||
const char *password = mpw_askpass( prompt );
|
||||
if (password)
|
||||
return password;
|
||||
|
||||
// Get password from terminal.
|
||||
char *answer = getpass( prompt );
|
||||
if (!answer)
|
||||
return NULL;
|
||||
|
||||
password = strdup( answer );
|
||||
mpw_zero( answer, strlen( answer ) );
|
||||
return password;
|
||||
return _mpw_getline( prompt, true );
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
|
||||
// Resolve user's home directory.
|
||||
char *homeDir = NULL;
|
||||
if (!homeDir)
|
||||
if ((homeDir = getenv( "HOME" )))
|
||||
homeDir = strdup( homeDir );
|
||||
homeDir = mpw_strdup( homeDir );
|
||||
if (!homeDir)
|
||||
if ((homeDir = getenv( "USERPROFILE" )))
|
||||
homeDir = strdup( homeDir );
|
||||
homeDir = mpw_strdup( homeDir );
|
||||
if (!homeDir) {
|
||||
const char *homeDrive = getenv( "HOMEDRIVE" ), *homePath = getenv( "HOMEPATH" );
|
||||
if (homeDrive && homePath)
|
||||
homeDir = strdup( mpw_str( "%s%s", homeDrive, homePath ) );
|
||||
homeDir = mpw_strdup( mpw_str( "%s%s", homeDrive, homePath ) );
|
||||
}
|
||||
if (!homeDir) {
|
||||
struct passwd *passwd = getpwuid( getuid() );
|
||||
if (passwd)
|
||||
homeDir = strdup( passwd->pw_dir );
|
||||
homeDir = mpw_strdup( passwd->pw_dir );
|
||||
}
|
||||
if (!homeDir)
|
||||
homeDir = getcwd( NULL, 0 );
|
||||
|
||||
// Compose filename.
|
||||
char *path = strdup( mpw_str( "%s.%s", prefix, extension ) );
|
||||
char *path = mpw_strdup( mpw_str( "%s.%s", prefix, extension ) );
|
||||
|
||||
// This is a filename, remove all potential directory separators.
|
||||
for (char *slash; (slash = strstr( path, "/" )); *slash = '_');
|
||||
@@ -173,32 +210,31 @@ const char *mpw_path(const char *prefix, const char *extension) {
|
||||
free( path );
|
||||
|
||||
if (homePath)
|
||||
path = strdup( homePath );
|
||||
path = mpw_strdup( homePath );
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
if (!filePath)
|
||||
return false;
|
||||
|
||||
// The path to mkdir is the filePath without the last path component.
|
||||
char *pathEnd = strrchr( filePath, '/' );
|
||||
char *path = pathEnd? strndup( filePath, (size_t)(pathEnd - filePath) ): NULL;
|
||||
if (!path)
|
||||
return false;
|
||||
|
||||
// Save the cwd and for absolute paths, start at the root.
|
||||
char *cwd = getcwd( NULL, 0 );
|
||||
if (*filePath == '/')
|
||||
chdir( "/" );
|
||||
if (chdir( "/" ) == ERR)
|
||||
return false;
|
||||
|
||||
// The path to mkdir is the filePath without the last path component.
|
||||
char *pathEnd = strrchr( filePath, '/' );
|
||||
if (pathEnd)
|
||||
return true;
|
||||
|
||||
// Walk the path.
|
||||
bool success = true;
|
||||
char *path = mpw_strndup( filePath, (size_t)(pathEnd - filePath) );
|
||||
for (char *dirName = strtok( path, "/" ); success && dirName; dirName = strtok( NULL, "/" )) {
|
||||
if (!strlen( dirName ))
|
||||
continue;
|
||||
@@ -214,8 +250,6 @@ bool mpw_mkdirs(const char *filePath) {
|
||||
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 *buf = NULL;
|
||||
@@ -229,8 +263,6 @@ char *mpw_read_fd(int fd) {
|
||||
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) {
|
||||
|
||||
if (!file)
|
||||
@@ -244,3 +276,73 @@ char *mpw_read_file(FILE *file) {
|
||||
|
||||
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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "mpw-types.h"
|
||||
|
||||
#ifndef MP_VERSION
|
||||
#define MP_VERSION ?
|
||||
@@ -62,3 +63,7 @@ char *mpw_read_fd(int fd);
|
||||
/** Read the file contents of a given file.
|
||||
* @return A newly allocated string or NULL the read buffer couldn't be allocated. */
|
||||
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);
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
@@ -273,51 +275,51 @@ void cli_free(Arguments *args, Operation *operation) {
|
||||
void cli_args(Arguments *args, Operation *operation, const int argc, char *const argv[]) {
|
||||
|
||||
for (int opt; (opt = getopt( argc, argv, "u:U:m:M:t:P:c:a:p:C:f:F:R:vqh" )) != EOF;
|
||||
optarg? mpw_zero( optarg, strlen( optarg ) ): NULL)
|
||||
optarg? mpw_zero( optarg, strlen( optarg ) ): (void)0)
|
||||
switch (opt) {
|
||||
case 'u':
|
||||
args->fullName = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->fullName = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
operation->allowPasswordUpdate = false;
|
||||
break;
|
||||
case 'U':
|
||||
args->fullName = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->fullName = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
operation->allowPasswordUpdate = true;
|
||||
break;
|
||||
case 'm':
|
||||
args->masterPasswordFD = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->masterPasswordFD = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
break;
|
||||
case 'M':
|
||||
// Passing your master password via the command-line is insecure. Testing purposes only.
|
||||
args->masterPassword = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->masterPassword = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
break;
|
||||
case 't':
|
||||
args->resultType = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->resultType = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
break;
|
||||
case 'P':
|
||||
args->resultParam = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->resultParam = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
break;
|
||||
case 'c':
|
||||
args->siteCounter = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->siteCounter = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
break;
|
||||
case 'a':
|
||||
args->algorithmVersion = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->algorithmVersion = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
break;
|
||||
case 'p':
|
||||
args->keyPurpose = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->keyPurpose = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
break;
|
||||
case 'C':
|
||||
args->keyContext = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->keyContext = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
break;
|
||||
case 'f':
|
||||
args->sitesFormat = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->sitesFormat = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
operation->sitesFormatFixed = false;
|
||||
break;
|
||||
case 'F':
|
||||
args->sitesFormat = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->sitesFormat = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
operation->sitesFormatFixed = true;
|
||||
break;
|
||||
case 'R':
|
||||
args->sitesRedacted = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||
args->sitesRedacted = optarg && strlen( optarg )? mpw_strdup( optarg ): NULL;
|
||||
break;
|
||||
case 'v':
|
||||
++mpw_verbosity;
|
||||
@@ -349,13 +351,13 @@ void cli_args(Arguments *args, Operation *operation, const int argc, char *const
|
||||
}
|
||||
|
||||
if (optind < argc && argv[optind])
|
||||
args->siteName = strdup( argv[optind] );
|
||||
args->siteName = mpw_strdup( argv[optind] );
|
||||
}
|
||||
|
||||
void cli_fullName(Arguments *args, Operation *operation) {
|
||||
|
||||
if ((!operation->fullName || !strlen( operation->fullName )) && args->fullName)
|
||||
operation->fullName = strdup( args->fullName );
|
||||
operation->fullName = mpw_strdup( args->fullName );
|
||||
|
||||
if (!operation->fullName || !strlen( operation->fullName ))
|
||||
do {
|
||||
@@ -378,7 +380,7 @@ void cli_masterPassword(Arguments *args, Operation *operation) {
|
||||
}
|
||||
|
||||
if ((!operation->masterPassword || !strlen( operation->masterPassword )) && args->masterPassword)
|
||||
operation->masterPassword = strdup( args->masterPassword );
|
||||
operation->masterPassword = mpw_strdup( args->masterPassword );
|
||||
|
||||
if (!operation->masterPassword || !strlen( operation->masterPassword ))
|
||||
do {
|
||||
@@ -395,7 +397,7 @@ void cli_masterPassword(Arguments *args, Operation *operation) {
|
||||
void cli_siteName(Arguments *args, Operation *operation) {
|
||||
|
||||
if ((!operation->siteName || !strlen( operation->siteName )) && args->siteName)
|
||||
operation->siteName = strdup( args->siteName );
|
||||
operation->siteName = mpw_strdup( args->siteName );
|
||||
if (!operation->siteName || !strlen( operation->siteName ))
|
||||
do {
|
||||
operation->siteName = mpw_getline( "Site name:" );
|
||||
@@ -439,7 +441,7 @@ void cli_keyContext(Arguments *args, Operation *operation) {
|
||||
if (!args->keyContext)
|
||||
return;
|
||||
|
||||
operation->keyContext = strdup( args->keyContext );
|
||||
operation->keyContext = mpw_strdup( args->keyContext );
|
||||
}
|
||||
|
||||
void cli_user(Arguments *args, Operation *operation) {
|
||||
@@ -495,7 +497,7 @@ void cli_user(Arguments *args, Operation *operation) {
|
||||
}
|
||||
if (operation->user) {
|
||||
mpw_free_string( &operation->user->masterPassword );
|
||||
operation->user->masterPassword = strdup( operation->masterPassword );
|
||||
operation->user->masterPassword = mpw_strdup( operation->masterPassword );
|
||||
}
|
||||
}
|
||||
mpw_free_string( &sitesInputData );
|
||||
@@ -550,7 +552,7 @@ void cli_question(Arguments __unused *args, Operation *operation) {
|
||||
case MPKeyPurposeRecovery:
|
||||
for (size_t q = 0; !operation->question && q < operation->site->questions_count; ++q)
|
||||
if ((!operation->keyContext && !strlen( (&operation->site->questions[q])->keyword )) ||
|
||||
(operation->keyContext && strcmp( (&operation->site->questions[q])->keyword, operation->keyContext ) != 0))
|
||||
(operation->keyContext && strcmp( (&operation->site->questions[q])->keyword, operation->keyContext ) == 0))
|
||||
operation->question = &operation->site->questions[q];
|
||||
|
||||
// If no question from mpsites, create a new one.
|
||||
@@ -562,7 +564,7 @@ void cli_question(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)
|
||||
abort();
|
||||
@@ -571,23 +573,23 @@ void cli_operation(Arguments __unused *args, Operation *operation) {
|
||||
case MPKeyPurposeAuthentication: {
|
||||
operation->purposeResult = "password";
|
||||
operation->resultType = operation->site->type;
|
||||
operation->resultState = operation->site->content? strdup( operation->site->content ): NULL;
|
||||
operation->resultState = operation->site->content? mpw_strdup( operation->site->content ): NULL;
|
||||
operation->siteCounter = operation->site->counter;
|
||||
break;
|
||||
}
|
||||
case MPKeyPurposeIdentification: {
|
||||
operation->purposeResult = "login";
|
||||
operation->resultType = operation->site->loginType;
|
||||
operation->resultState = operation->site->loginContent? strdup( operation->site->loginContent ): NULL;
|
||||
operation->resultState = operation->site->loginContent? mpw_strdup( operation->site->loginContent ): NULL;
|
||||
operation->siteCounter = MPCounterValueInitial;
|
||||
break;
|
||||
}
|
||||
case MPKeyPurposeRecovery: {
|
||||
mpw_free_string( &operation->keyContext );
|
||||
operation->purposeResult = "answer";
|
||||
operation->keyContext = operation->question->keyword? strdup( operation->question->keyword ): NULL;
|
||||
operation->keyContext = operation->question->keyword? mpw_strdup( operation->question->keyword ): NULL;
|
||||
operation->resultType = operation->question->type;
|
||||
operation->resultState = operation->question->content? strdup( operation->question->content ): NULL;
|
||||
operation->resultState = operation->question->content? mpw_strdup( operation->question->content ): NULL;
|
||||
operation->siteCounter = MPCounterValueInitial;
|
||||
break;
|
||||
}
|
||||
@@ -653,7 +655,7 @@ void cli_resultParam(Arguments *args, Operation *operation) {
|
||||
if (!args->resultParam)
|
||||
return;
|
||||
|
||||
operation->resultParam = strdup( args->resultParam );
|
||||
operation->resultParam = mpw_strdup( args->resultParam );
|
||||
}
|
||||
|
||||
void cli_algorithmVersion(Arguments *args, Operation *operation) {
|
||||
@@ -713,18 +715,18 @@ void cli_mpw(Arguments *args, Operation *operation) {
|
||||
switch (operation->keyPurpose) {
|
||||
case MPKeyPurposeAuthentication: {
|
||||
mpw_free_string( &operation->site->content );
|
||||
operation->site->content = strdup( operation->resultState );
|
||||
operation->site->content = mpw_strdup( operation->resultState );
|
||||
break;
|
||||
}
|
||||
case MPKeyPurposeIdentification: {
|
||||
mpw_free_string( &operation->site->loginContent );
|
||||
operation->site->loginContent = strdup( operation->resultState );
|
||||
operation->site->loginContent = mpw_strdup( operation->resultState );
|
||||
break;
|
||||
}
|
||||
|
||||
case MPKeyPurposeRecovery: {
|
||||
mpw_free_string( &operation->question->content );
|
||||
operation->question->content = strdup( operation->resultState );
|
||||
operation->question->content = mpw_strdup( operation->resultState );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -735,7 +737,7 @@ void cli_mpw(Arguments *args, Operation *operation) {
|
||||
|
||||
// resultParam defaults to state.
|
||||
if (!operation->resultParam && operation->resultState)
|
||||
operation->resultParam = strdup( operation->resultState );
|
||||
operation->resultParam = mpw_strdup( operation->resultState );
|
||||
|
||||
// Generate result.
|
||||
const char *result = mpw_siteResult( masterKey, operation->site->name, operation->siteCounter,
|
||||
|
||||
@@ -261,7 +261,10 @@ chr() {
|
||||
# Outputs the decimal ASCII value of the given character.
|
||||
#
|
||||
ord() {
|
||||
printf '%d' "'$1"
|
||||
local str=$1 s
|
||||
for (( s=0; s < ${#str}; ++s )); do
|
||||
printf '%d' "'${str:s:1}"
|
||||
done
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
@@ -274,7 +277,10 @@ ord() {
|
||||
# Outputs the hexadecimal ASCII value of the given character.
|
||||
#
|
||||
hex() {
|
||||
printf '%x' "'$1"
|
||||
local str=$1 s
|
||||
for (( s=0; s < ${#str}; ++s )); do
|
||||
printf '%02X' "'${str:s:1}"
|
||||
done
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
@@ -287,7 +293,10 @@ hex() {
|
||||
# Outputs the character that has the given hexadecimal ASCII value.
|
||||
#
|
||||
unhex() {
|
||||
printf "\\x$1"
|
||||
local hex=$1 h
|
||||
for (( h=0; h < ${#hex}; h+=2 )); do
|
||||
printf "\\x${hex:h:2}"
|
||||
done
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
@@ -1422,6 +1431,29 @@ shorten() {
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ CdSource ________________________________________________________________|
|
||||
#
|
||||
# cdsource [file]
|
||||
#
|
||||
# Change the current directory into the directory where the file is located, resolving symlinks.
|
||||
#
|
||||
cdsource() {
|
||||
local source=${1:-${BASH_SOURCE[1]}}
|
||||
|
||||
while [[ $source ]]; do
|
||||
[[ $source = */* ]] && cd "${source%/*}"
|
||||
|
||||
if [[ -L ${source##*/} ]]; then
|
||||
source=$(readlink "${source##*/}")
|
||||
else
|
||||
source=
|
||||
fi
|
||||
done
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ Up ________________________________________________________________|
|
||||
#
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source bashlib
|
||||
cdsource
|
||||
|
||||
getword() {
|
||||
local cat=$1 pop_limit=$2 words=()
|
||||
@@ -19,9 +21,7 @@ declare -A categoryByCharacter=(
|
||||
['v']=verb
|
||||
)
|
||||
templates=(
|
||||
nvan
|
||||
anvr
|
||||
anavan
|
||||
ran # ~32.0 bit
|
||||
)
|
||||
permutations=1
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
mpw-2.6-cli-3-0-g0ff6c93a.tar.gz
|
||||
mpw-2.6-cli-3-0-ga85eff42.tar.gz
|
||||
@@ -1 +1 @@
|
||||
mpw-2.6-cli-3-0-g0ff6c93a.tar.gz.sig
|
||||
mpw-2.6-cli-3-0-ga85eff42.tar.gz.sig
|
||||
Binary file not shown.
Binary file not shown.
BIN
public/site/2013-05/mpw-2.6-cli-3-0-ga85eff42.tar.gz
Normal file
BIN
public/site/2013-05/mpw-2.6-cli-3-0-ga85eff42.tar.gz
Normal file
Binary file not shown.
BIN
public/site/2013-05/mpw-2.6-cli-3-0-ga85eff42.tar.gz.sig
Normal file
BIN
public/site/2013-05/mpw-2.6-cli-3-0-ga85eff42.tar.gz.sig
Normal file
Binary file not shown.
Reference in New Issue
Block a user