Skip to content

Commit 0711965

Browse files
authored
refactor: remove deleteOldFiles() #3701
Problem: - Date-triggered tech debt test started failing, which reminds us to remove old code. - This code also was producing (harmless) failures which show up in logs (example: #3403): ``` [WARN]: auth: error deleting old files in sso cache: Error: ENOENT: no such file or directory, scandir 'C:\Users\user.aws\sso\cache' [ENOENT] ``` Solution: Remove deleteOldFiles().
1 parent 6ceb5bf commit 0711965

File tree

3 files changed

+4
-137
lines changed

3 files changed

+4
-137
lines changed

src/auth/sso/cache.ts

Lines changed: 3 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { hasProps, selectFrom } from '../../shared/utilities/tsUtils'
1212
import { SsoToken, ClientRegistration } from './model'
1313
import { SystemUtilities } from '../../shared/systemUtilities'
1414
import { DevSettings } from '../../shared/settings'
15-
import { statSync, Stats, readdirSync, unlinkSync } from 'fs'
1615

1716
interface RegistrationKey {
1817
readonly region: string
@@ -34,46 +33,13 @@ export interface SsoCache {
3433
const defaultCacheDir = path.join(SystemUtilities.getHomeDirectory(), '.aws', 'sso', 'cache')
3534
export const getCacheDir = () => DevSettings.instance.get('ssoCacheDirectory', defaultCacheDir)
3635

37-
export function getCache(directory = getCacheDir(), statFunc = getFileStats): SsoCache {
38-
try {
39-
deleteOldFiles(directory, statFunc)
40-
} catch (e) {
41-
getLogger().warn('auth: error deleting old files in sso cache: %s', e)
42-
}
43-
36+
export function getCache(directory = getCacheDir()): SsoCache {
4437
return {
4538
token: getTokenCache(directory),
4639
registration: getRegistrationCache(directory),
4740
}
4841
}
4942

50-
function deleteOldFiles(directory: string, statFunc: typeof getFileStats) {
51-
if (!isDirSafeToDeleteFrom(directory)) {
52-
getLogger().warn(`Skipped deleting files in directory: ${path.resolve(directory)}`)
53-
return
54-
}
55-
56-
const fileNames = readdirSync(directory)
57-
fileNames.forEach(fileName => {
58-
const filePath = path.join(directory, fileName)
59-
if (path.extname(filePath) === '.json' && isOldFile(filePath, statFunc)) {
60-
unlinkSync(filePath)
61-
getLogger().warn(`auth: removed old cache file: ${filePath}`)
62-
}
63-
})
64-
}
65-
66-
export function isDirSafeToDeleteFrom(dirPath: string): boolean {
67-
const resolvedPath = path.resolve(dirPath)
68-
const isRoot = resolvedPath === path.resolve('/')
69-
const isCwd = resolvedPath === path.resolve('.')
70-
const isAbsolute = path.isAbsolute(dirPath)
71-
const pathDepth = resolvedPath.split(path.sep).length
72-
73-
const isSafe = !isRoot && !isCwd && isAbsolute && pathDepth >= 5
74-
return isSafe
75-
}
76-
7743
export function getRegistrationCache(directory = getCacheDir()): KeyedCache<ClientRegistration, RegistrationKey> {
7844
// Compatability for older Toolkit versions (format on disk is unchanged)
7945
type StoredRegistration = Omit<ClientRegistration, 'expiresAt'> & { readonly expiresAt: string }
@@ -144,30 +110,7 @@ export function getTokenCache(directory = getCacheDir()): KeyedCache<SsoAccess>
144110
return mapCache(cache, read, write)
145111
}
146112

147-
function getFileStats(file: string): Stats {
148-
return statSync(file)
149-
}
150-
151-
const firstValidDate = new Date(2023, 3, 14) // April 14, 2023
152-
153-
/**
154-
* @returns true if file is older than the first valid date
155-
*/
156-
function isOldFile(file: string, statFunc: typeof getFileStats): boolean {
157-
try {
158-
const statResult = statFunc(file)
159-
// Depending on the Windows filesystem, birthtime may be 0, so we fall back to ctime (last time metadata was changed)
160-
// https://nodejs.org/api/fs.html#stat-time-values
161-
return statResult.birthtimeMs !== 0
162-
? statResult.birthtimeMs < firstValidDate.getTime()
163-
: statResult.ctime < firstValidDate
164-
} catch (err) {
165-
getLogger().debug(`SSO cache file age not be verified: ${file}: ${err}`)
166-
return false // Assume it is no old since we cannot validate
167-
}
168-
}
169-
170-
export function getTokenCacheFile(ssoCacheDir: string, ssoUrl: string): string {
113+
function getTokenCacheFile(ssoCacheDir: string, ssoUrl: string): string {
171114
const encoded = encodeURI(ssoUrl)
172115
// Per the spec: 'SSO Login Token Flow' the access token must be
173116
// cached as the SHA1 hash of the bytes of the UTF-8 encoded
@@ -183,7 +126,7 @@ export function getTokenCacheFile(ssoCacheDir: string, ssoUrl: string): string {
183126
return path.join(ssoCacheDir, `${hashedUrl}.json`)
184127
}
185128

186-
export function getRegistrationCacheFile(ssoCacheDir: string, key: RegistrationKey): string {
129+
function getRegistrationCacheFile(ssoCacheDir: string, key: RegistrationKey): string {
187130
const hashScopes = (scopes: string[]) => {
188131
const shasum = crypto.createHash('sha256')
189132
scopes.forEach(s => shasum.update(s))

src/test/credentials/sso/ssoAccessTokenProvider.test.ts

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as FakeTimers from '@sinonjs/fake-timers'
88
import * as sinon from 'sinon'
99
import { SsoAccessTokenProvider } from '../../../auth/sso/ssoAccessTokenProvider'
1010
import { installFakeClock } from '../../testUtil'
11-
import { getCache, getTokenCacheFile, isDirSafeToDeleteFrom, getRegistrationCacheFile } from '../../../auth/sso/cache'
11+
import { getCache } from '../../../auth/sso/cache'
1212

1313
import { instance, mock, when, anything, reset } from '../../utilities/mockito'
1414
import { makeTemporaryToolkitFolder, tryRemoveFolder } from '../../../shared/filesystemUtilities'
@@ -124,74 +124,6 @@ describe('SsoAccessTokenProvider', function () {
124124
assert.strictEqual(await cache.token.load(startUrl), undefined)
125125
})
126126

127-
describe('does not return old tokens', function () {
128-
// A file is old when the creation time is under a certain date
129-
const oldTime: Date = new Date(2023, 3, 10) // April 10, 2023
130-
const nonOldTime: Date = new Date(2023, 3, 15) // April 15, 2023
131-
132-
function oldBirthtime(file: fs.PathLike): fs.Stats {
133-
return { birthtimeMs: oldTime.getTime(), birthtime: oldTime } as fs.Stats
134-
}
135-
136-
/** Windows edge case where birthtime does not exist, instead check ctime */
137-
function noBirthtimeOldCTime(file: fs.PathLike): fs.Stats {
138-
return { birthtimeMs: 0, ctime: oldTime } as fs.Stats
139-
}
140-
141-
const oldStatsFuncs = [oldBirthtime, noBirthtimeOldCTime]
142-
143-
oldStatsFuncs.forEach(invalidStatsFunc => {
144-
it(`deletes old invalid tokens when ${invalidStatsFunc.name} then returns undefined`, async function () {
145-
await cache.token.save(startUrl, { region, startUrl, token: createToken(hourInMs) })
146-
const tokenCacheFile = getTokenCacheFile(tempDir, startUrl)
147-
assert.strictEqual(fs.existsSync(tokenCacheFile), true)
148-
149-
// Set the func which returns Stats that are always 'invalid'
150-
cache = getCache(tempDir, invalidStatsFunc)
151-
152-
assert.strictEqual(await cache.token.load(startUrl), undefined)
153-
assert.strictEqual(fs.existsSync(tokenCacheFile), false)
154-
})
155-
156-
it(`deletes old invalid registrations when ${invalidStatsFunc.name} then returns undefined`, async function () {
157-
const registrationKey = { region }
158-
await cache.registration.save(registrationKey, createRegistration(hourInMs))
159-
const registrationCacheFile = getRegistrationCacheFile(tempDir, registrationKey)
160-
assert.strictEqual(fs.existsSync(registrationCacheFile), true)
161-
162-
// Set the func which returns Stats that are always 'invalid'
163-
cache = getCache(tempDir, invalidStatsFunc)
164-
assert.strictEqual(await cache.token.load(startUrl), undefined)
165-
assert.strictEqual(fs.existsSync(registrationCacheFile), false)
166-
})
167-
})
168-
169-
function nonOldBirthtime(file: fs.PathLike): fs.Stats {
170-
return { birthtimeMs: nonOldTime.getTime() } as fs.Stats
171-
}
172-
173-
it(`returns token from non-old file`, async function () {
174-
const token = createToken(hourInMs)
175-
await cache.token.save(startUrl, { region, startUrl, token })
176-
const tokenCacheFile = getTokenCacheFile(tempDir, startUrl)
177-
assert.strictEqual(fs.existsSync(tokenCacheFile), true)
178-
179-
cache = getCache(tempDir, nonOldBirthtime)
180-
181-
assert.deepStrictEqual((await cache.token.load(startUrl))!.token, token)
182-
assert.strictEqual(fs.existsSync(tokenCacheFile), true)
183-
})
184-
185-
it('isDirSafeToDeleteFrom()', function () {
186-
assert.ok(!isDirSafeToDeleteFrom('.'))
187-
assert.ok(!isDirSafeToDeleteFrom('/'))
188-
assert.ok(!isDirSafeToDeleteFrom('not/an/absolute/path'))
189-
assert.ok(!isDirSafeToDeleteFrom('/a/b/c')) // Too shallow
190-
191-
assert.ok(isDirSafeToDeleteFrom('/a/b/c/d'))
192-
})
193-
})
194-
195127
it('returns `undefined` for expired tokens that cannot be refreshed', async function () {
196128
const expiredToken = createToken(-hourInMs)
197129
await cache.token.save(startUrl, { region, startUrl, token: expiredToken })

src/test/techdebt.test.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,4 @@ describe('tech debt', function () {
4242
'with node16+, we can use crypto.randomUUID and remove the "uuid" dependency'
4343
)
4444
})
45-
46-
it('temporary code removed', function () {
47-
// Reason: https://sim.amazon.com/issues/IDE-10559
48-
// At this point in time most users who would have run in to this error
49-
// will have already had their old files deleted.
50-
const august2023 = new Date(2023, 7, 1)
51-
assert.ok(Date.now() < august2023.getTime(), 'remove `deleteOldFiles()` in `cache.ts`')
52-
})
5345
})

0 commit comments

Comments
 (0)