diff --git a/src/agents/collector/external-accounts.sql b/src/agents/collector/external-accounts.sql index c086a50..ddba84c 100644 --- a/src/agents/collector/external-accounts.sql +++ b/src/agents/collector/external-accounts.sql @@ -1,5 +1,13 @@ PRAGMA foreign_keys = ON; +CREATE TABLE IF NOT EXISTS external_account_secrets ( + id TEXT PRIMARY KEY, + owner TEXT NOT NULL, + secret TEXT NOT NULL, + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL +); + CREATE TABLE IF NOT EXISTS external_accounts ( id INTEGER PRIMARY KEY, owner TEXT NOT NULL, diff --git a/src/agents/collector/external_accounts.c b/src/agents/collector/external_accounts.c index d6576ce..47ba0de 100644 --- a/src/agents/collector/external_accounts.c +++ b/src/agents/collector/external_accounts.c @@ -152,3 +152,60 @@ CollectorAccountsMarkResult(sqlite3 *database, sqlite3_int64 id, long now, sqlite3_finalize(statement); return result ? 0 : -1; } + +int +CollectorAccountsSecretSet(sqlite3 *database, const char *id, + const char *owner, const char *secret, long now) +{ + sqlite3_stmt *statement = NULL; + const char query[] = "INSERT INTO external_account_secrets " + "(id, owner, secret, created_at, updated_at) VALUES (?, ?, ?, ?, ?) " + "ON CONFLICT(id) DO UPDATE SET owner=excluded.owner, secret=excluded.secret, " + "updated_at=excluded.updated_at"; + int result; + if (database == NULL || id == NULL || owner == NULL || secret == NULL || + sqlite3_prepare_v2(database, query, -1, &statement, NULL) != SQLITE_OK) return -1; + sqlite3_bind_text(statement, 1, id, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 2, owner, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 3, secret, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 4, (sqlite3_int64) now); + sqlite3_bind_int64(statement, 5, (sqlite3_int64) now); + result = sqlite3_step(statement) == SQLITE_DONE ? 0 : -1; + sqlite3_finalize(statement); + return result; +} + +int +CollectorAccountsSecretGet(sqlite3 *database, const char *id, + char *secret, size_t secret_size) +{ + sqlite3_stmt *statement = NULL; + const char query[] = "SELECT secret FROM external_account_secrets WHERE id = ?"; + int result; + if (database == NULL || id == NULL || secret == NULL || secret_size == 0 || + sqlite3_prepare_v2(database, query, -1, &statement, NULL) != SQLITE_OK) return -1; + secret[0] = '\0'; + sqlite3_bind_text(statement, 1, id, -1, SQLITE_TRANSIENT); + result = sqlite3_step(statement); + if (result == SQLITE_ROW) { + const char *value = (const char *) sqlite3_column_text(statement, 0); + if (value == NULL || snprintf(secret, secret_size, "%s", value) >= (int) secret_size) result = -1; + else result = 1; + } else if (result == SQLITE_DONE) result = 0; + else result = -1; + sqlite3_finalize(statement); + return result; +} + +int +CollectorAccountsSecretDelete(sqlite3 *database, const char *id) +{ + sqlite3_stmt *statement = NULL; + const char query[] = "DELETE FROM external_account_secrets WHERE id = ?"; + int result; + if (database == NULL || id == NULL || sqlite3_prepare_v2(database, query, -1, &statement, NULL) != SQLITE_OK) return -1; + sqlite3_bind_text(statement, 1, id, -1, SQLITE_TRANSIENT); + result = sqlite3_step(statement) == SQLITE_DONE ? 0 : -1; + sqlite3_finalize(statement); + return result; +} diff --git a/src/agents/collector/external_accounts.h b/src/agents/collector/external_accounts.h index 79e6216..1f2e6d9 100644 --- a/src/agents/collector/external_accounts.h +++ b/src/agents/collector/external_accounts.h @@ -26,5 +26,10 @@ int CollectorAccountsNextDue(sqlite3 *database, long now, CollectorExternalAccount *account); int CollectorAccountsMarkResult(sqlite3 *database, sqlite3_int64 id, long now, int success, const char *error); +int CollectorAccountsSecretSet(sqlite3 *database, const char *id, + const char *owner, const char *secret, long now); +int CollectorAccountsSecretGet(sqlite3 *database, const char *id, + char *secret, size_t secret_size); +int CollectorAccountsSecretDelete(sqlite3 *database, const char *id); #endif