diff --git a/modules/local-kms/build.gradle.kts b/modules/local-kms/build.gradle.kts index c771ff60..87061f17 100644 --- a/modules/local-kms/build.gradle.kts +++ b/modules/local-kms/build.gradle.kts @@ -1,3 +1,6 @@ +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig +import kotlin.apply + plugins { kotlin("multiplatform") version "2.0.0" id("app.cash.sqldelight") version "2.0.2" @@ -30,6 +33,22 @@ sqldelight { kotlin { jvm() + js { + browser { + commonWebpackConfig { + devServer = KotlinWebpackConfig.DevServer().apply { + port = 8083 + } + } + } + nodejs { + testTask { + useMocha { + timeout = "5000" + } + } + } + } sourceSets { commonMain { @@ -49,13 +68,13 @@ kotlin { } } -// jsMain { -// dependencies { -// implementation(npm("typescript", "5.5.3")) -// implementation(npm("jose", "5.6.3")) -// implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") -// } -// } + jsMain { + dependencies { + implementation(npm("typescript", "5.5.3")) + implementation(npm("jose", "5.6.3")) + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") + } + } jvmTest { dependencies { diff --git a/modules/local-kms/src/commonMain/sqldelight/com/sphereon/oid/fed/kms/local/models/1.sqm b/modules/local-kms/src/commonMain/sqldelight/com/sphereon/oid/fed/kms/local/models/1.sqm index aaee9711..cb48ff6d 100644 --- a/modules/local-kms/src/commonMain/sqldelight/com/sphereon/oid/fed/kms/local/models/1.sqm +++ b/modules/local-kms/src/commonMain/sqldelight/com/sphereon/oid/fed/kms/local/models/1.sqm @@ -1,5 +1,5 @@ CREATE TABLE Keys ( id TEXT PRIMARY KEY, key TEXT NOT NULL, - deleted_at TIMESTAMP + deleted_at BIGINT ); diff --git a/modules/local-kms/src/jsMain/kotlin/com/sphereon/oid/fed/kms/local/database/LocalKmsDatabase.js.kt b/modules/local-kms/src/jsMain/kotlin/com/sphereon/oid/fed/kms/local/database/LocalKmsDatabase.js.kt new file mode 100644 index 00000000..7aab0e68 --- /dev/null +++ b/modules/local-kms/src/jsMain/kotlin/com/sphereon/oid/fed/kms/local/database/LocalKmsDatabase.js.kt @@ -0,0 +1,75 @@ +package com.sphereon.oid.fed.kms.local.database + +import app.cash.sqldelight.db.QueryResult +import app.cash.sqldelight.db.SqlCursor +import app.cash.sqldelight.db.SqlDriver +import com.sphereon.oid.fed.kms.local.Constants +import com.sphereon.oid.fed.kms.local.Database +import com.sphereon.oid.fed.kms.local.models.Keys + + +actual class LocalKmsDatabase { + + private var database: Database + + init { + val driver = getDriver() + runMigrations(driver) + + database = Database(driver) + } + + private fun getDriver(): SqlDriver { + return PlatformSqlDriver().createPostgresDriver( + System.getenv(Constants.LOCAL_KMS_DATASOURCE_URL), + System.getenv(Constants.LOCAL_KMS_DATASOURCE_USER), + System.getenv(Constants.LOCAL_KMS_DATASOURCE_PASSWORD) + ) + } + + private fun runMigrations(driver: SqlDriver) { + setupSchemaVersioningTable(driver) + + val currentVersion = getCurrentDatabaseVersion(driver) + val newVersion = Database.Schema.version + + if (currentVersion < newVersion) { + Database.Schema.migrate(driver, currentVersion, newVersion) + updateDatabaseVersion(driver, newVersion) + } + } + + private fun setupSchemaVersioningTable(driver: SqlDriver) { + driver.execute(null, "CREATE TABLE IF NOT EXISTS schema_version (version INTEGER NOT NULL)", 0) + } + + private fun getCurrentDatabaseVersion(driver: SqlDriver): Long { + val versionQuery = "SELECT version FROM schema_version ORDER BY version DESC LIMIT 1" + + val version = driver.executeQuery(null, versionQuery, parameters = 0, mapper = { cursor: SqlCursor -> + QueryResult.Value(if (cursor.next().value) cursor.getLong(0) else null) + }) + + return version.value ?: 0 + } + + private fun updateDatabaseVersion(driver: SqlDriver, newVersion: Long) { + val updateQuery = "INSERT INTO schema_version (version) VALUES (?)" + driver.execute(null, updateQuery, 1) { + bindLong(0, newVersion) + } + } + + actual fun getKey(keyId: String): Keys { + return database.keysQueries.findById(keyId).executeAsOneOrNull() + ?: throw KeyNotFoundException("$keyId not found") + } + + actual fun insertKey(keyId: String, key: String) { + database.keysQueries.create(keyId, key).executeAsOneOrNull() + } + + actual fun deleteKey(keyId: String) { + database.keysQueries.delete(keyId) + } +} diff --git a/modules/local-kms/src/jsMain/kotlin/com/sphereon/oid/fed/kms/local/database/PlatformSqlDriver.kt b/modules/local-kms/src/jsMain/kotlin/com/sphereon/oid/fed/kms/local/database/PlatformSqlDriver.kt new file mode 100644 index 00000000..1bc99f62 --- /dev/null +++ b/modules/local-kms/src/jsMain/kotlin/com/sphereon/oid/fed/kms/local/database/PlatformSqlDriver.kt @@ -0,0 +1,14 @@ +package com.sphereon.oid.fed.kms.local.database + +import app.cash.sqldelight.db.SqlDriver +import com.sphereon.oid.fed.kms.local.Constants + +actual class PlatformSqlDriver { + actual fun createPostgresDriver(url: String, username: String, password: String): SqlDriver { + throw UnsupportedOperationException(Constants.POSTGRESQL_IS_NOT_SUPPORTED_IN_JS) as Throwable + } + + actual fun createSqliteDriver(path: String): SqlDriver { + throw UnsupportedOperationException(Constants.SQLITE_IS_NOT_SUPPORTED_IN_JS) + } +}