test_that("specify keyring explicitly", { dir.create(tmp <- tempfile()) on.exit(unlink(tmp, recursive = TRUE)) withr::local_options(list(keyring_file_dir = tmp)) service_1 <- random_service() username <- random_username() password <- random_password() password2 <- random_password() keyring <- random_keyring() kb <- backend_file$new(keyring = keyring) kb$keyring_create(keyring, "secret123!") expect_false(kb$keyring_is_locked(keyring)) kb$keyring_lock(keyring) expect_true(kb$keyring_is_locked(keyring)) expect_silent(kb$keyring_unlock(keyring, password = "secret123!")) expect_false(kb$keyring_is_locked(keyring)) ## Missing expect_error(kb$get(service_1, username), "could not be found") expect_silent(kb$set_with_value(service_1, username, password)) expect_equal(kb$get(service_1, username), password) ## Missing expect_error(kb$get(service_1, "foobar"), "could not be found") ## Overwrite expect_silent(kb$set_with_value(service_1, username, password2)) expect_equal(kb$get(service_1, username), password2) expect_silent(kb$set_with_value(random_service(), username, password)) long_password <- random_string(500L) service_2 <- random_service() expect_silent(kb$set_with_value(service_2, username, long_password)) expect_equal(kb$get(service_2, username), long_password) ## Delete expect_silent(kb$delete(service_1, username)) expect_error(kb$get(service_1, username), "could not be found") ## Delete non-existent is silent expect_silent(kb$delete(service_1, username)) expect_silent(kb$keyring_delete()) }) test_that("key consistency check", { username <- random_username() password <- random_password() keyring <- random_keyring() dir.create(tmp <- tempfile()) on.exit(unlink(tmp, recursive = TRUE), add = TRUE) withr::local_options(list(keyring_file_dir = tmp)) keyring_pwd_1 <- random_password() keyring_pwd_2 <- random_password() kb <- backend_file$new(keyring = keyring) kb$keyring_create(keyring, keyring_pwd_1) expect_silent(kb$keyring_unlock(password = keyring_pwd_1)) expect_silent(kb$set_with_value(random_service(), username, password)) expect_error( kb$keyring_unlock(password = keyring_pwd_2), "cannot unlock keyring" ) expect_silent(kb$keyring_lock()) expect_error( kb$keyring_unlock(password = keyring_pwd_2), "cannot unlock keyring" ) kb$.__enclos_env__$private$set_keyring_pass(keyring_pwd_2) expect_true(kb$keyring_is_locked()) kb$.__enclos_env__$private$unset_keyring_pass() expect_silent(kb$keyring_delete()) }) test_that("use non-default keyring", { dir.create(tmp <- tempfile()) on.exit(unlink(tmp, recursive = TRUE), add = TRUE) withr::local_options(list(keyring_file_dir = tmp)) service <- random_service() username <- random_username() password <- random_password() default_keyring <- random_keyring() keyring <- random_keyring() default_keyring_pwd <- random_password() keyring_pwd <- random_password() kb <- backend_file$new(keyring = default_keyring) kb$keyring_create(password = default_keyring_pwd) kb$keyring_create(keyring, keyring_pwd) expect_silent(kb$keyring_unlock(password = default_keyring_pwd)) expect_false(kb$keyring_is_locked()) expect_silent(kb$keyring_unlock(keyring, keyring_pwd)) expect_false(kb$keyring_is_locked(keyring)) expect_false(kb$keyring_is_locked()) expect_silent(kb$set_with_value(service, username, password, keyring)) expect_equal(kb$get(service, username, keyring), password) expect_silent( all_items <- kb$list(keyring = keyring) ) expect_s3_class(all_items, "data.frame") expect_equal(nrow(all_items), 1L) expect_named(all_items, c("service", "username")) expect_silent(kb$keyring_delete()) expect_silent(kb$keyring_delete(keyring)) }) test_that("list keyring items", { dir.create(tmp <- tempfile()) on.exit(unlink(tmp, recursive = TRUE), add = TRUE) withr::local_options(list(keyring_file_dir = tmp)) service <- random_service() username <- random_username() keyring <- random_keyring() keyring_pwd <- random_password() kb <- backend_file$new(keyring) kb$keyring_create(keyring, keyring_pwd) expect_silent(kb$keyring_unlock(password = keyring_pwd)) expect_silent(kb$set_with_value( random_service(), random_username(), random_password() )) expect_silent(kb$set_with_value( service, random_username(), random_password() )) expect_silent(kb$set_with_value( service, random_username(), random_password() )) expect_silent( all_items <- kb$list() ) expect_s3_class(all_items, "data.frame") expect_equal(nrow(all_items), 3L) expect_named(all_items, c("service", "username")) expect_silent( some_items <- kb$list(service) ) expect_s3_class(some_items, "data.frame") expect_equal(nrow(some_items), 2L) expect_named(some_items, c("service", "username")) invisible(sapply(some_items[["service"]], expect_identical, service)) expect_silent(kb$keyring_delete(keyring)) }) test_that("helper functions work", { secret <- random_password() long_secret <- random_string(500L) nonce <- sodium_random(24L) password <- sodium_hash(charToRaw(random_password())) expect_identical(b_file_split_string(secret), secret) expect_true( is_string( split_key <- b_file_split_string(long_secret) ) ) expect_match(split_key, "\\n") expect_identical(b_file_merge_string(split_key), long_secret) expect_identical( b_file_secret_decrypt( b_file_secret_encrypt(secret, nonce, password), nonce, password ), secret ) expect_identical( b_file_secret_decrypt( b_file_secret_encrypt(long_secret, nonce, password), nonce, password ), long_secret ) }) test_that("keys updated from another session", { skip_on_cran() dir.create(tmp <- tempfile()) on.exit(unlink(tmp, recursive = TRUE), add = TRUE) withr::local_options(list(keyring_file_dir = tmp)) service_1 <- random_service() username <- random_username() username2 <- random_username() password <- random_password() password2 <- random_password() keyring <- random_keyring() kb <- backend_file$new(keyring = keyring) kb$keyring_create(keyring, "foobar") kb$keyring_unlock(password = "foobar") kb$set_with_value(service_1, username, password) ret <- callr::r( function(s, u, p, k, dir) { options(keyring_file_dir = dir) kb <- keyring::backend_file$new(keyring = k) kb$keyring_unlock(password = "foobar") kb$set_with_value(s, u, p) kb$get(s, u) }, args = list( s = service_1, u = username2, p = password2, k = keyring, dir = tmp ) ) expect_equal(ret, password2) expect_equal(kb$get(service_1, username), password) expect_equal(kb$get(service_1, username2), password2) expect_equal(kb$get(service_1, username), password) }) test_that("locking the keyring file", { skip_on_cran() dir.create(tmp <- tempfile()) on.exit(unlink(tmp, recursive = TRUE), add = TRUE) withr::local_options(list(keyring_file_dir = tmp)) service_1 <- random_service() username <- random_username() password <- random_password() keyring <- random_keyring() kb <- backend_file$new(keyring = keyring) kb$keyring_create(password = "foobar") lockfile <- paste0(kb$.__enclos_env__$private$keyring_file(), ".lck") rb <- callr::r_bg( function(lf) { l <- filelock::lock(lf) cat("done\n") Sys.sleep(3) }, args = list(lf = lockfile), stdout = "|" ) on.exit(rb$kill(), add = TRUE) rb$poll_io(3000) withr::with_options( list(keyring_file_lock_timeout = 100), expect_snapshot( error = TRUE, kb$set_with_value(service_1, username, password) ) ) }) test_that("keyring does not exist", { dir.create(tmp <- tempfile()) on.exit(unlink(tmp, recursive = TRUE)) withr::local_options(list(keyring_file_dir = tmp)) kb <- backend_file$new() expect_snapshot(error = TRUE, { kb$list() kb$keyring_is_locked() kb$keyring_unlock() kb$set_with_value("service", "user", "pass") }) })