diff --git a/scripts/tests/e3/rules.lua b/scripts/tests/e3/rules.lua index a4ee0ea3f..896c8a0c7 100644 --- a/scripts/tests/e3/rules.lua +++ b/scripts/tests/e3/rules.lua @@ -929,6 +929,7 @@ function test_volcanooutbreak_message() assert_not_equal("", msg:render("en")) end +<<<<<<< HEAD function test_bug2083() local herb_multi = 500 -- from rc_herb_trade() local r = region.create(0,0,"plain") @@ -961,7 +962,13 @@ function test_bug2083() assert_equal(0, u:get_item("balm")) end +======= +>>>>>>> release-3.7.11 function test_no_uruk() local f1 = faction.create("noreply@eressea.de", "uruk", "de") assert_equal(f1.race, "orc") end +<<<<<<< HEAD +======= + +>>>>>>> release-3.7.11 diff --git a/src/buildno.h b/src/buildno.h index 9727f88eb..3ce9dbfe7 100644 --- a/src/buildno.h +++ b/src/buildno.h @@ -1,3 +1,3 @@ #define VERSION_MAJOR 3 #define VERSION_MINOR 8 -#define VERSION_BUILD 3 +#define VERSION_BUILD 4 diff --git a/src/kernel/save.c b/src/kernel/save.c index fe8fbd93d..9623aaefd 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1154,6 +1154,58 @@ void write_spellbook(const struct spellbook *book, struct storage *store) WRITE_TOK(store, "end"); } +static char * getpasswd(int fno) { + const char *prefix = itoa36(fno); + size_t len = strlen(prefix); + FILE * F = fopen("passwords.txt", "r"); + char line[80]; + if (F) { + while (!feof(F)) { + fgets(line, sizeof(line), F); + if (line[len]==':' && strncmp(prefix, line, len)==0) { + size_t slen = strlen(line)-1; + assert(line[slen]=='\n'); + line[slen] = 0; + fclose(F); + return _strdup(line+len+1); + } + } + fclose(F); + } + return NULL; +} + +static void read_password(gamedata *data, faction *f) { + char name[128]; + READ_STR(data->store, name, sizeof(name)); + if (data->version == BADCRYPT_VERSION) { + char * pass = getpasswd(f->no); + if (pass) { + faction_setpassword(f, password_hash(pass, 0, PASSWORD_DEFAULT)); + free(pass); // TODO: remove this allocation! + } + else { + free(f->_password); + f->_password = NULL; + } + } + else { + faction_setpassword(f, (data->version >= CRYPT_VERSION) ? name : password_hash(name, 0, PASSWORD_DEFAULT)); + } +} + +void _test_read_password(gamedata *data, faction *f) { + read_password(data, f); +} + +static void write_password(gamedata *data, const faction *f) { + WRITE_TOK(data->store, (const char *)f->_password); +} + +void _test_write_password(gamedata *data, const faction *f) { + write_password(data, f); +} + /** Reads a faction from a file. * This function requires no context, can be called in any state. The * faction may not already exist, however. @@ -1220,8 +1272,7 @@ faction *readfaction(struct gamedata * data) set_email(&f->email, ""); } - READ_STR(data->store, name, sizeof(name)); - faction_setpassword(f, (data->version > CRYPT_VERSION) ? name : password_hash(name, 0, PASSWORD_DEFAULT)); + read_password(data, f); if (data->version < NOOVERRIDE_VERSION) { READ_STR(data->store, 0, 0); } @@ -1328,7 +1379,7 @@ void writefaction(struct gamedata *data, const faction * f) WRITE_STR(data->store, f->name); WRITE_STR(data->store, f->banner); WRITE_STR(data->store, f->email); - WRITE_TOK(data->store, f->_password); + write_password(data, f); WRITE_TOK(data->store, locale_name(f->locale)); WRITE_INT(data->store, f->lastorders); WRITE_INT(data->store, f->age); diff --git a/src/kernel/save.h b/src/kernel/save.h index ca364fc9c..cedd5befc 100644 --- a/src/kernel/save.h +++ b/src/kernel/save.h @@ -83,6 +83,9 @@ extern "C" { struct gamedata *gamedata_open(const char *filename, const char *mode); void gamedata_close(struct gamedata *data); + /* test-only functions that give access to internal implementation details (BAD) */ + void _test_write_password(struct gamedata *data, const struct faction *f); + void _test_read_password(struct gamedata *data, struct faction *f); #ifdef __cplusplus } #endif diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index e7f85ad7e..71cb6e91c 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -5,9 +5,14 @@ #include "unit.h" #include "faction.h" #include "version.h" +#include +#include + #include #include +#include + #include static void test_readwrite_data(CuTest * tc) @@ -42,15 +47,17 @@ static void test_readwrite_unit(CuTest * tc) u = test_create_unit(f, r); join_path(datapath(), filename, path, sizeof(path)); - data = gamedata_open(path, "w"); - CuAssertPtrNotNull(tc, data); // TODO: intermittent test + data = gamedata_open(path, "wb"); + CuAssertPtrNotNull(tc, data); + write_unit(data, u); gamedata_close(data); free_gamedata(); f = test_create_faction(0); renumber_faction(f, fno); - data = gamedata_open(path, "r"); + data = gamedata_open(path, "rb"); + CuAssertPtrNotNull(tc, data); u = read_unit(data); gamedata_close(data); @@ -61,10 +68,61 @@ static void test_readwrite_unit(CuTest * tc) test_cleanup(); } +static void test_read_password(CuTest *tc) { + const char *path = "test.dat"; + gamedata *data; + faction *f; + f = test_create_faction(0); + faction_setpassword(f, password_hash("secret", 0, PASSWORD_DEFAULT)); + data = gamedata_open(path, "wb"); + CuAssertPtrNotNull(tc, data); + _test_write_password(data, f); + gamedata_close(data); + data = gamedata_open(path, "rb"); + CuAssertPtrNotNull(tc, data); + _test_read_password(data, f); + gamedata_close(data); + CuAssertTrue(tc, checkpasswd(f, "secret")); + CuAssertIntEquals(tc, 0, remove(path)); +} + +static void test_read_password_external(CuTest *tc) { + const char *path = "test.dat", *pwfile = "passwords.txt"; + gamedata *data; + faction *f; + FILE * F; + + remove(pwfile); + f = test_create_faction(0); + faction_setpassword(f, password_hash("secret", 0, PASSWORD_DEFAULT)); + CuAssertPtrNotNull(tc, f->_password); + data = gamedata_open(path, "wb"); + CuAssertPtrNotNull(tc, data); + WRITE_TOK(data->store, (const char *)f->_password); + WRITE_TOK(data->store, (const char *)f->_password); + gamedata_close(data); + data = gamedata_open(path, "rb"); + CuAssertPtrNotNull(tc, data); + data->version = BADCRYPT_VERSION; + _test_read_password(data, f); + CuAssertPtrEquals(tc, 0, f->_password); + F = fopen(pwfile, "wt"); + fprintf(F, "%s:secret\n", itoa36(f->no)); + fclose(F); + _test_read_password(data, f); + CuAssertPtrNotNull(tc, f->_password); + gamedata_close(data); + CuAssertTrue(tc, checkpasswd(f, "secret")); + CuAssertIntEquals(tc, 0, remove(path)); + CuAssertIntEquals(tc, 0, remove(pwfile)); +} + CuSuite *get_save_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_readwrite_data); SUITE_ADD_TEST(suite, test_readwrite_unit); + SUITE_ADD_TEST(suite, test_read_password); + SUITE_ADD_TEST(suite, test_read_password_external); return suite; } diff --git a/src/kernel/version.h b/src/kernel/version.h index c18957530..3ff4e927a 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -33,9 +33,10 @@ #define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */ #define OWNER_3_VERSION 349 /* regions store last owner, not last alliance */ #define ATTRIBOWNER_VERSION 350 /* all attrib_type functions know who owns the attribute */ -#define CRYPT_VERSION 351 /* passwords are encrypted */ -#define RELEASE_VERSION CRYPT_VERSION /* current datafile */ +#define BADCRYPT_VERSION 351 /* passwords are encrypted, poorly */ +#define CRYPT_VERSION 352 /* passwords are encrypted */ +#define RELEASE_VERSION ATTRIBOWNER_VERSION /* current datafile */ #define MIN_VERSION INTPAK_VERSION /* minimal datafile we support */ -#define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */ +#define MAX_VERSION BADCRYPT_VERSION /* change this if we can need to read the future datafile, and we can do so */ #define STREAM_VERSION 2 /* internal encoding of binary files */