#include "pw.h" #include "tap.h" // posix for clock/timer functions #define _POSIX_C_SOURCE 200112L #include #include #include #include #include bool get_monotonic_timestamp(double *ts); int main(int argc, char **argv){ sqlite3 *db = NULL; int rc; if (argc != 2) { fprintf(stderr, "Usage: %s DATABASE\n", argv[0]); goto fail; } rc = sqlite3_open(argv[1], &db); if( rc ){ fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); goto fail; } pw_context *ctx; pw_init_context(db, &ctx); char *u1 = "foo@example.com", *p1 = "password123", *u1c = "FOO@EXAMPLE.COM"; plan(9); ok(PW_OK == pw_set(ctx, u1, p1), "pw_set"); ok(PW_OK == pw_check(ctx, u1, p1), "pw_check accepts the same credentials"); ok(PW_OK == pw_check(ctx, u1c, p1), "pw_check also accepts mixed case user"); ok(PW_BAD_PASS == pw_check(ctx, u1, "wrong"), "pw_check fails for wrong pass"); ok(PW_NO_USER == pw_check(ctx, "fake", "wrong"), "pw_check fails for missing user"); unsigned char *tok; unsigned int tok_len; ok(PW_OK == pw_token_create(ctx, u1, &tok, &tok_len), "pw_token_create can build one"); cmp_ok(tok_len, "==", 16, "token has expected length"); int i; double start, end, t_found, t_notfound, pct_diff; diag("check password 100 times"); get_monotonic_timestamp(&start); for (i = 0; i < 100; i++) pw_check(ctx, u1, p1); get_monotonic_timestamp(&end); t_found = end - start; diag("check 100 times for missing user"); get_monotonic_timestamp(&start); for (i = 0; i < 100; i++) pw_check(ctx, "fake", "wrong"); get_monotonic_timestamp(&end); t_notfound = end - start; pct_diff = 100.0 * fabs( (t_found - t_notfound) / ((t_found + t_notfound)/2) ); cmp_ok(pct_diff, "<", 1.0, "less than 1%% time difference"); free(ctx); sqlite3_close(db); return 0; fail: sqlite3_close(db); return EXIT_FAILURE; } // idea for using double representation taken from // https://github.com/solemnwarning/timespec #define NSEC_PER_SEC 1000000000 bool get_monotonic_timestamp(double *ts) { struct timespec now; int rc = clock_gettime(CLOCK_MONOTONIC, &now); if (rc != 0) return false; *ts = ( ((double)now.tv_sec) + (((double)now.tv_nsec) / NSEC_PER_SEC) ); return true; }