Skip to content

Commit 6b05689

Browse files
committed
Few improvements
1 parent a48a8ca commit 6b05689

3 files changed

Lines changed: 37 additions & 30 deletions

File tree

src/api/deviceAuth.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const createFetcher = (baseUrl: string) =>
4545
withHttpRetry
4646
)
4747

48-
export async function checkTenant(teamName: string): Promise<CheckTenantResponse> {
48+
export async function checkTenant(teamName: string): Promise<{ tenantUrl: string }> {
4949
const fetcher = createFetcher(LOGIN_SERVICE_URL)
5050
const response = await fetcher(`/api/check-tenant?name=${encodeURIComponent(teamName)}`, {
5151
method: 'GET',
@@ -55,7 +55,7 @@ export async function checkTenant(teamName: string): Promise<CheckTenantResponse
5555
// The check-tenant endpoint returns a redirect URL (e.g. http://tenant.localhost:5173/login).
5656
// Extract just the origin for use as the API base URL.
5757
const origin = new URL(data.redirectUrl).origin
58-
return { redirectUrl: origin }
58+
return { tenantUrl: origin }
5959
}
6060

6161
export async function requestDeviceCode(tenantUrl: string): Promise<DeviceCodeResponse> {

src/commands/auth.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import chalk from 'chalk'
33
import { ensureInteractive, prompt, promptHidden } from '../utils/prompt'
44
import { openBrowser } from '../utils/browser'
55
import { twirlLoader } from '../utils/misc'
6-
import { saveCredentials, clearCredentials, type CredentialSource } from '../utils/credentials'
6+
import {
7+
saveCredentials,
8+
clearCredentials,
9+
loadCredentialsFromKeyring,
10+
loadCredentialsFromFile,
11+
type CredentialSource,
12+
} from '../utils/credentials'
713
import { createApi } from '../api'
814
import {
915
checkTenant,
@@ -25,8 +31,8 @@ async function resolveTenantUrl(): Promise<string> {
2531
}
2632

2733
try {
28-
const result = await checkTenant(teamName)
29-
return result.redirectUrl
34+
const { tenantUrl } = await checkTenant(teamName)
35+
return tenantUrl
3036
} catch (e) {
3137
const message = e instanceof Error ? e.message : String(e)
3238
console.error(chalk.red('Error:') + ` Could not find team "${teamName}": ${message}`)
@@ -46,7 +52,7 @@ async function validateApiKey(tenantUrl: string, apiKey: string): Promise<boolea
4652

4753
async function handleApiKeyLogin(): Promise<void> {
4854
const tenantUrl = await resolveTenantUrl()
49-
const apiKey = await promptHidden('API Key: ')
55+
const apiKey = await promptHidden(`API Key ${chalk.gray('(Input Hidden)')}: `)
5056
if (!apiKey) {
5157
console.error(chalk.red('Error:') + ' API key is required.')
5258
process.exit(1)
@@ -156,10 +162,26 @@ const sourceLabels: Partial<Record<CredentialSource, string>> = {
156162
'.env': 'a .env file in the current directory',
157163
'.qaspherecli': 'a .qaspherecli file',
158164
}
165+
async function findClearableSource(): Promise<'keyring' | 'credentials.json' | null> {
166+
if (await loadCredentialsFromKeyring()) return 'keyring'
167+
if (loadCredentialsFromFile()) return 'credentials.json'
168+
return null
169+
}
170+
159171
async function handleLogout(): Promise<void> {
160-
const result = await clearCredentials()
172+
const clearable = await findClearableSource()
173+
174+
if (clearable) {
175+
try {
176+
await clearCredentials(clearable)
177+
} catch (e) {
178+
const message = e instanceof Error ? e.message : String(e)
179+
console.error(
180+
chalk.red('Error:') + ` Could not clear credentials from ${clearable}: ${message}`
181+
)
182+
process.exit(1)
183+
}
161184

162-
if (result.cleared) {
163185
console.log('Logged out.')
164186

165187
// Warn if credentials are still available from another source
@@ -175,7 +197,7 @@ async function handleLogout(): Promise<void> {
175197
return
176198
}
177199

178-
// Check if credentials come from a non-clearable source
200+
// No clearable source — check if credentials come from a non-clearable source
179201
const source = await resolveCredentialSource()
180202
if (source) {
181203
const label = sourceLabels[source.source] || source.source

src/utils/credentials.ts

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -108,27 +108,12 @@ export function loadCredentialsFromFile(): StoredCredentials | null {
108108
}
109109
}
110110

111-
export async function clearCredentials(): Promise<{
112-
cleared: boolean
113-
source?: CredentialSource
114-
}> {
115-
// Try keyring first
116-
const entry = await getKeyringEntry()
117-
if (entry) {
118-
try {
119-
entry.getPassword() // Throws if no entry exists
120-
entry.deletePassword()
121-
return { cleared: true, source: 'keyring' }
122-
} catch {
123-
// No keyring entry or keyring unavailable, continue to file
124-
}
125-
}
126-
127-
// Try file
128-
if (existsSync(CREDENTIALS_FILE)) {
111+
export async function clearCredentials(source: 'keyring' | 'credentials.json'): Promise<void> {
112+
if (source === 'keyring') {
113+
const entry = await getKeyringEntry()
114+
if (!entry) throw new Error('Keyring is not available')
115+
entry.deletePassword()
116+
} else {
129117
unlinkSync(CREDENTIALS_FILE)
130-
return { cleared: true, source: 'credentials.json' }
131118
}
132-
133-
return { cleared: false }
134119
}

0 commit comments

Comments
 (0)