-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(storage): add credentials store scafolding and update types #13558
Changes from all commits
80ecee7
33426e4
cf8e783
8787d63
52a52ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
describe('createLocationCredentialsStore', () => { | ||
it.todo('should create a store'); | ||
describe('created store', () => { | ||
describe('getValue()', () => { | ||
it.todo('should call getValue() from store'); | ||
it.todo( | ||
'should validate credentials location with resolved common scope', | ||
); | ||
}); | ||
describe('destroy()', () => { | ||
it.todo('should call removeStore() from store'); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* eslint-disable unused-imports/no-unused-vars */ | ||
|
||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
describe('createStore', () => { | ||
it.todo('should create a store with given capacity, refresh Handler'); | ||
it.todo('should return a symbol to refer the store instance'); | ||
}); | ||
|
||
describe('getValue', () => { | ||
it.todo('should look up a cache value for given location and permission'); | ||
it.todo( | ||
'should look up a cache value for given location and READWRITE permission', | ||
); | ||
it.todo('should invoke the refresh handler if look up returns null'); | ||
it.todo( | ||
'should invoke refresh handler only once if multiple look up for same location returns null', | ||
); | ||
it.todo('should throw if refresh handler throws'); | ||
it.todo( | ||
'should invoke the refresh handler if the refresh handler previously fails', | ||
); | ||
}); | ||
|
||
describe('removeStore', () => { | ||
it.todo('should remove the store with given symbol'); | ||
it.todo('should not throw if store with given symbol does not exist'); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
describe('initStore', () => { | ||
it.todo( | ||
'should create a store with given capacity, refresh Handler and cache', | ||
); | ||
it.todo('should create a store with default capacity if not provided'); | ||
it.todo('should throw if capacity is not > 0'); | ||
}); | ||
|
||
describe('getCacheKey', () => { | ||
it.todo('should return a cache key for given location and permission'); | ||
}); | ||
|
||
describe('getCacheValue', () => { | ||
it.todo('should return a cache value for given location and permission'); | ||
it.todo('should return null if cache value is not found'); | ||
it.todo('should return null if cache value is expired'); | ||
it.todo('should return null if cache value is not valid'); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,4 +7,8 @@ export { | |
ListCallerAccessGrantsOutput, | ||
} from './listCallerAccessGrants'; | ||
export { createLocationCredentialsHandler } from './createLocationCredentialsHandler'; | ||
export { createLocationCredentialsStore } from './locationCredentialsStore/createLocationCredentialsStore'; | ||
export { createLocationCredentialsStore } from './locationCredentialsStore/create'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I think I prefer the old way, naming the file the same as the utility it contains is a pretty normal pattern in the lib (don't feel strongly, not a blocker) |
||
export { | ||
managedAuthAdapter, | ||
ManagedAuthAdapterInput, | ||
} from './managedAuthAdapter'; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,45 @@ | ||||||
/* eslint-disable unused-imports/no-unused-vars */ | ||||||
|
||||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||||||
// SPDX-License-Identifier: Apache-2.0 | ||||||
|
||||||
import { | ||||||
CredentialsLocation, | ||||||
LocationCredentialsHandler, | ||||||
LocationCredentialsStore, | ||||||
} from '../types'; | ||||||
import { LocationCredentialsProvider } from '../../providers/s3/types/options'; | ||||||
|
||||||
import { createStore, getValue, removeStore } from './registry'; | ||||||
|
||||||
export const createLocationCredentialsStore = (input: { | ||||||
handler: LocationCredentialsHandler; | ||||||
}): LocationCredentialsStore => { | ||||||
const storeReference = createStore(input.handler); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit since this isn't actually a reference to the store
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense. will address this in the implementation PR. |
||||||
|
||||||
const store = { | ||||||
getProvider(providerLocation: CredentialsLocation) { | ||||||
const locationCredentialsProvider = async ({ | ||||||
permission, | ||||||
locations, | ||||||
forceRefresh = false, | ||||||
}: Parameters<LocationCredentialsProvider>[0]) => { | ||||||
// TODO(@AllanZhengYP) validate input | ||||||
|
||||||
return getValue({ | ||||||
storeReference, | ||||||
location: { ...providerLocation }, | ||||||
forceRefresh, | ||||||
}); | ||||||
}; | ||||||
|
||||||
return locationCredentialsProvider; | ||||||
}, | ||||||
|
||||||
destroy() { | ||||||
removeStore(storeReference); | ||||||
}, | ||||||
}; | ||||||
|
||||||
return store; | ||||||
}; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* eslint-disable unused-imports/no-unused-vars */ | ||
|
||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
import { AWSCredentials } from '@aws-amplify/core/internals/utils'; | ||
|
||
import { CredentialsLocation, LocationCredentialsHandler } from '../types'; | ||
|
||
import { LocationCredentialsStore, initStore } from './store'; | ||
|
||
/** | ||
* Keep all cache records for all instances of credentials store in a singleton | ||
* so we can reliably de-reference from the memory when we destroy a store | ||
* instance. | ||
*/ | ||
const storeRegistry = new Map<symbol, LocationCredentialsStore>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not to use WeakMap to ensure an automatic GC when the registry key is dereferenced? |
||
|
||
export const createStore = ( | ||
refreshHandler: LocationCredentialsHandler, | ||
size?: number, | ||
) => { | ||
const storeInstanceSymbol = Symbol('LocationCredentialsStore'); | ||
storeRegistry.set(storeInstanceSymbol, initStore(refreshHandler, size)); | ||
|
||
return storeInstanceSymbol; | ||
}; | ||
|
||
export const getValue = async (input: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. This is already done in the following implementation PR |
||
storeReference: symbol; | ||
location: CredentialsLocation; | ||
forceRefresh: boolean; | ||
}): Promise<{ credentials: AWSCredentials }> => { | ||
// TODO(@AllanZhengYP): get location credentials from store. | ||
throw new Error('Not implemented'); | ||
}; | ||
|
||
export const removeStore = (storeReference: symbol) => { | ||
storeRegistry.delete(storeReference); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* eslint-disable unused-imports/no-unused-vars */ | ||
|
||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
import { AWSCredentials } from '@aws-amplify/core/internals/utils'; | ||
|
||
import { Permission } from '../../providers/s3/types/options'; | ||
import { CredentialsLocation, LocationCredentialsHandler } from '../types'; | ||
|
||
const CREDENTIALS_STORE_DEFAULT_SIZE = 10; | ||
|
||
export interface StoreValue extends CredentialsLocation { | ||
credentials?: AWSCredentials; | ||
inflightCredentials?: Promise<{ credentials: AWSCredentials }>; | ||
} | ||
|
||
type S3Url = string; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export type CacheKey = `${S3Url}_${Permission}`; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export const getCacheKey = (compositeKey: CredentialsLocation): CacheKey => | ||
`${compositeKey.scope}_${compositeKey.permission}`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sanity check: Will weird customer defined delimiters mess with this at all? E.g. if a customer uses ` or _ Everything would already be URL encoded right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Delimiter does not affect the caching key since a different delimiter refers to a different object. |
||
|
||
/** | ||
* LRU implementation for Location Credentials Store | ||
* O(n) for get and set for simplicity. | ||
* | ||
* @internal | ||
*/ | ||
export interface LocationCredentialsStore { | ||
capacity: number; | ||
refreshHandler: LocationCredentialsHandler; | ||
values: Map<CacheKey, StoreValue>; | ||
} | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export const initStore = ( | ||
refreshHandler: LocationCredentialsHandler, | ||
size = CREDENTIALS_STORE_DEFAULT_SIZE, | ||
): LocationCredentialsStore => { | ||
// TODO(@AllanZhengYP) create StorageError | ||
if (size <= 0) { | ||
throw new Error('Invalid Cache size'); | ||
} | ||
|
||
return { | ||
capacity: size, | ||
refreshHandler, | ||
values: new Map<CacheKey, StoreValue>(), | ||
}; | ||
}; | ||
|
||
export const getCacheValue = ( | ||
store: LocationCredentialsStore, | ||
key: CacheKey, | ||
): AWSCredentials | null => { | ||
throw new Error('Not implemented'); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
import { | ||
CredentialsProvider, | ||
ListLocations, | ||
LocationCredentialsHandler, | ||
} from './types'; | ||
|
||
export interface ManagedAuthAdapterInput { | ||
accountId: string; | ||
region: string; | ||
credentialsProvider: CredentialsProvider; | ||
} | ||
|
||
export interface ManagedAuthAdapterOutput { | ||
listLocations: ListLocations; | ||
getLocationCredentials: LocationCredentialsHandler; | ||
region: string; | ||
} | ||
|
||
export const managedAuthAdapter = ( | ||
// eslint-disable-next-line unused-imports/no-unused-vars | ||
input: ManagedAuthAdapterInput, | ||
): ManagedAuthAdapterOutput => { | ||
// TODO(@AllanZhengYP) | ||
throw new Error('Not implemented'); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love all these todos!