Skip to content

Commit 9316ec5

Browse files
Adding ?apiKey= to connection string #66
1 parent 507d204 commit 9316ec5

File tree

12 files changed

+101
-49
lines changed

12 files changed

+101
-49
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@
22
# chinook database used in non-destructive tests
33
CHINOOK_DATABASE_URL="sqlitecloud://user:password@xxx.sqlite.cloud:8860/chinook.sqlite"
44

5+
# api key used to test login w/o username and password
6+
CHINOOK_API_KEY=xxxxxx
7+
58
# sqlite cloud gateway for socket.io connections
69
GATEWAY_URL=ws://localhost:4000

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sqlitecloud/drivers",
3-
"version": "0.0.56",
3+
"version": "0.0.57",
44
"description": "SQLiteCloud drivers for Typescript/Javascript in edge, web and node clients",
55
"main": "./lib/index.js",
66
"types": "./lib/index.d.ts",

scripts/gateway-build.sh

Lines changed: 0 additions & 15 deletions
This file was deleted.

scripts/gateway-upgrade.sh

Lines changed: 0 additions & 19 deletions
This file was deleted.

scripts/sqlitecloud-cli

-2.59 MB
Binary file not shown.

src/drivers/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export interface SQLiteCloudConfig {
2020
password?: string
2121
/** True if password is hashed, default is false */
2222
passwordHashed?: boolean
23+
/** API key can be provided instead of username and password */
24+
apiKey?: string
2325

2426
/** Host name is required unless connectionString is provided, eg: xxx.sqlitecloud.io */
2527
host?: string

src/drivers/utilities.ts

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@ export function anonimizeError(error: Error): Error {
3636
/** Initialization commands sent to database when connection is established */
3737
export function getInitializationCommands(config: SQLiteCloudConfig): string {
3838
// first user authentication, then all other commands
39-
let commands = `AUTH USER ${config.username || ''} ${config.passwordHashed ? 'HASH' : 'PASSWORD'} ${config.password || ''}; `
39+
let commands = ''
40+
41+
if (config.apiKey) {
42+
commands = `AUTH APIKEY ${config.apiKey}; `
43+
} else {
44+
commands = `AUTH USER ${config.username || ''} ${config.passwordHashed ? 'HASH' : 'PASSWORD'} ${config.password || ''}; `
45+
}
4046

4147
if (config.database) {
4248
if (config.createDatabase && !config.dbMemory) {
@@ -192,23 +198,32 @@ export function validateConfiguration(config: SQLiteCloudConfig): SQLiteCloudCon
192198
config.nonlinearizable = parseBoolean(config.nonlinearizable)
193199
config.insecure = parseBoolean(config.insecure)
194200

195-
if (!config.username || !config.password || !config.host) {
201+
const hasCredentials = (config.username && config.password) || config.apiKey
202+
if (!config.host || !hasCredentials) {
196203
console.error('SQLiteCloudConnection.validateConfiguration - missing arguments', config)
197-
throw new SQLiteCloudError('The user, password and host arguments must be specified.', { errorCode: 'ERR_MISSING_ARGS' })
204+
throw new SQLiteCloudError('The user, password and host arguments or the ?apiKey= must be specified.', { errorCode: 'ERR_MISSING_ARGS' })
198205
}
199206

200207
if (!config.connectionString) {
201208
// build connection string from configuration, values are already validated
202209
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
203-
config.connectionString = `sqlitecloud://${encodeURIComponent(config.username)}:${encodeURIComponent(config.password)}@${config.host}:${config.port}/${
204-
config.database
205-
}`
210+
if (config.apiKey) {
211+
config.connectionString = `sqlitecloud://${config.host}:${config.port}/${config.database || ''}?apiKey=${config.apiKey}`
212+
} else {
213+
config.connectionString = `sqlitecloud://${encodeURIComponent(config.username || '')}:${encodeURIComponent(config.password || '')}@${config.host}:${
214+
config.port
215+
}/${config.database}`
216+
}
206217
}
207218

208219
return config
209220
}
210221

211-
/** Parse connectionString like sqlitecloud://username:password@host:port/database?option1=xxx&option2=xxx into its components */
222+
/**
223+
* Parse connectionString like sqlitecloud://username:password@host:port/database?option1=xxx&option2=xxx
224+
* or sqlitecloud://host.sqlite.cloud:8860/chinook.sqlite?apiKey=mIiLARzKm9XBVllbAzkB1wqrgijJ3Gx0X5z1Agm3xBo
225+
* into its basic components.
226+
*/
212227
export function parseConnectionString(connectionString: string): SQLiteCloudConfig {
213228
try {
214229
// The URL constructor throws a TypeError if the URL is not valid.
@@ -232,6 +247,15 @@ export function parseConnectionString(connectionString: string): SQLiteCloudConf
232247
...options
233248
}
234249

250+
// either you use an apiKey or username and password
251+
if (config.apiKey) {
252+
if (config.username || config.password) {
253+
console.warn('SQLiteCloudConnection.parseConnectionString - apiKey and username/password are both specified, using apiKey')
254+
}
255+
delete config.username
256+
delete config.password
257+
}
258+
235259
const database = url.pathname.replace('/', '') // pathname is database name, remove the leading slash
236260
if (database) {
237261
config.database = database

test/connection-tls.test.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
LONG_TIMEOUT,
1313
getTestingConfig,
1414
getChinookConfig,
15+
getChinookApiKeyUrl,
1516
getChinookTlsConnection,
1617
sendCommandsAsync,
1718
// clearTestingDatabasesAsync,
@@ -74,6 +75,32 @@ describe('connection-tls', () => {
7475
LONG_TIMEOUT
7576
)
7677

78+
it(
79+
'should connect using api key',
80+
done => {
81+
try {
82+
// eg: sqlitecloud://mIiLARzKm9XBVllbAzkB1wqrgijJ3Gx0X5z1Agm3xBo@host.sqlite.cloud:8860/chinook.sqlite
83+
const connectionUrl = getChinookApiKeyUrl()
84+
const connection = new SQLiteCloudTlsConnection(connectionUrl, error => {
85+
expect(error).toBeNull()
86+
expect(connection.connected).toBe(true)
87+
88+
connection.sendCommands('TEST STRING', (error, results) => {
89+
connection.close()
90+
expect(connection.connected).toBe(false)
91+
done()
92+
})
93+
})
94+
expect(connection).toBeDefined()
95+
} catch (error) {
96+
console.error(`An error occurred while connecting using api key: ${error}`)
97+
debugger
98+
throw error
99+
}
100+
},
101+
LONG_TIMEOUT
102+
)
103+
77104
it('should connect with connection string', done => {
78105
// if (CHINOOK_DATABASE_URL.indexOf('localhost') > 0) {
79106
// // skip this test when running locally since it requires a self-signed certificate
@@ -128,7 +155,7 @@ describe('connection-tls', () => {
128155
expect(error).toBeDefined()
129156
expect(error).toBeInstanceOf(SQLiteCloudError)
130157
const sqliteCloudError = error as SQLiteCloudError
131-
expect(sqliteCloudError.message).toBe('The user, password and host arguments must be specified.')
158+
expect(sqliteCloudError.message).toBe('The user, password and host arguments or the ?apiKey= must be specified.')
132159
expect(sqliteCloudError.errorCode).toBe('ERR_MISSING_ARGS')
133160
expect(sqliteCloudError.externalErrorCode).toBeUndefined()
134161
expect(sqliteCloudError.offsetCode).toBeUndefined()
@@ -524,7 +551,7 @@ describe('connection-tls', () => {
524551
chinook.sendCommands('LIST METADATA;', (error, results) => {
525552
expect(error).toBeNull()
526553
expect(results.numberOfColumns).toBe(8)
527-
expect(results.numberOfRows).toBe(64)
554+
expect(results.numberOfRows).toBeGreaterThanOrEqual(32)
528555

529556
done()
530557
chinook.close()
@@ -594,7 +621,7 @@ describe('connection-tls', () => {
594621
chinook.sendCommands('SELECT * FROM tracks;', (error, results) => {
595622
expect(error).toBeNull()
596623
expect(results.numberOfColumns).toBe(9)
597-
expect(results.numberOfRows).toBe(3503)
624+
expect(results.numberOfRows).toBeGreaterThan(3000) // 3503 tracks but we sometimes test deleting rows
598625

599626
done()
600627
chinook.close()

test/connection-ws.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ describe('connection-ws', () => {
306306
chinook.sendCommands('LIST METADATA;', (error, results) => {
307307
expect(error).toBeNull()
308308
expect(results.numberOfColumns).toBe(8)
309-
expect(results.numberOfRows).toBe(64)
309+
expect(results.numberOfRows).toBeGreaterThanOrEqual(32)
310310
done()
311311
})
312312
})
@@ -363,7 +363,7 @@ describe('connection-ws', () => {
363363
chinook.sendCommands('SELECT * FROM tracks;', (error, results) => {
364364
expect(error).toBeNull()
365365
expect(results.numberOfColumns).toBe(9)
366-
expect(results.numberOfRows).toBe(3503)
366+
expect(results.numberOfRows).toBeGreaterThan(3000) // 3503 tracks but we sometimes test deleting rows
367367
done()
368368
})
369369
})

0 commit comments

Comments
 (0)