Send credentials on open_project (#9468)

- Close https://github.com/enso-org/cloud-v2/issues/1038
- Send credentials for libs to use, when opening projects against the Cloud (Remote) backend.

# Important Notes
None
This commit is contained in:
somebody1234 2024-04-02 16:47:35 +10:00 committed by GitHub
parent 11e1e9efa0
commit 4c7c20ad08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 52 additions and 12 deletions

View File

@ -37,6 +37,8 @@ import * as detect from 'enso-common/src/detect'
import type * as loggerProvider from '#/providers/LoggerProvider'
import * as dateTime from '#/utilities/dateTime'
import * as service from '#/authentication/service'
// =================
@ -48,6 +50,8 @@ import * as service from '#/authentication/service'
* This provider alone requires a string because it is not a standard provider, and thus has no
* constant defined in the AWS Amplify library. */
const GITHUB_PROVIDER = 'Github'
/** One second, in milliseconds. */
const SEC_MS = 1_000
// ================
// === UserInfo ===
@ -376,7 +380,7 @@ export interface UserSession {
/** URL to refresh the access token. */
readonly refreshUrl: string
/** Time when the access token will expire, date and time in ISO 8601 format (UTC timezone). */
readonly expireAt: string
readonly expireAt: dateTime.Rfc3339DateTime
/** Cognito app integration client id.. */
readonly clientId: string
}
@ -393,11 +397,7 @@ function parseUserSession(session: cognito.CognitoUserSession, clientId: string)
} else {
const expirationTimestamp = session.getAccessToken().getExpiration()
const expireAt = (() => {
const date = new Date(0)
date.setUTCSeconds(expirationTimestamp)
return date.toISOString()
})()
const expireAt = dateTime.toRfc3339(new Date(expirationTimestamp * SEC_MS))
return {
email,

View File

@ -13,6 +13,7 @@ import * as toastAndLogHooks from '#/hooks/toastAndLogHooks'
import * as authProvider from '#/providers/AuthProvider'
import * as backendProvider from '#/providers/BackendProvider'
import * as modalProvider from '#/providers/ModalProvider'
import * as sessionProvider from '#/providers/SessionProvider'
import * as textProvider from '#/providers/TextProvider'
import type * as assetEvent from '#/events/assetEvent'
@ -82,6 +83,7 @@ export default function ProjectIcon(props: ProjectIconProps) {
const { keyProp: key, item, setItem, assetEvents, doOpenManually } = props
const { doCloseEditor, doOpenEditor } = props
const { backend } = backendProvider.useBackend()
const { session } = sessionProvider.useSession()
const { user } = authProvider.useNonPartialUserSession()
const { unsetModal } = modalProvider.useSetModal()
const toastAndLog = toastAndLogHooks.useToastAndLog()
@ -145,7 +147,11 @@ export default function ProjectIcon(props: ProjectIconProps) {
}
await backend.openProject(
item.id,
{ executeAsync: shouldRunInBackground, parentId: item.parentId },
{
executeAsync: shouldRunInBackground,
parentId: item.parentId,
cognitoCredentials: session,
},
item.title
)
}
@ -165,7 +171,11 @@ export default function ProjectIcon(props: ProjectIconProps) {
case backendModule.BackendType.local: {
await backend.openProject(
item.id,
{ executeAsync: shouldRunInBackground, parentId: item.parentId },
{
executeAsync: shouldRunInBackground,
parentId: item.parentId,
cognitoCredentials: null,
},
item.title
)
setState(oldState =>
@ -188,6 +198,7 @@ export default function ProjectIcon(props: ProjectIconProps) {
backend,
item,
closeProjectAbortController,
session,
toastAndLog,
/* should never change */ setState,
/* should never change */ setItem,

View File

@ -360,6 +360,15 @@ export interface Version {
readonly version_type: VersionType
}
/** Credentials that need to be passed to libraries to give them access to the Cloud API. */
export interface CognitoCredentials {
readonly accessToken: string
readonly refreshToken: string
readonly refreshUrl: string
readonly clientId: string
readonly expireAt: dateTime.Rfc3339DateTime
}
/** Subscription plans. */
export enum Plan {
solo = 'solo',
@ -958,6 +967,8 @@ export interface UpdateProjectRequestBody {
/** HTTP request body for the "open project" endpoint. */
export interface OpenProjectRequestBody {
readonly executeAsync: boolean
/** MUST be present on Remote backend; NOT REQUIRED on Local backend. */
readonly cognitoCredentials: CognitoCredentials | null
/** Only used by the Local backend. */
readonly parentId: DirectoryId
}

View File

@ -601,13 +601,29 @@ export default class RemoteBackend extends Backend {
): Promise<void> {
const body = object.omit(bodyRaw, 'parentId')
const path = remoteBackendPaths.openProjectPath(projectId)
const response = await this.post(path, body)
if (body.cognitoCredentials == null) {
return this.throw(null, 'openProjectMissingCredentialsBackendError', title)
} else {
const credentials = body.cognitoCredentials
const exactCredentials: backendModule.CognitoCredentials = {
accessToken: credentials.accessToken,
clientId: credentials.clientId,
expireAt: credentials.expireAt,
refreshToken: credentials.refreshToken,
refreshUrl: credentials.refreshUrl,
}
const filteredBody: Omit<backendModule.OpenProjectRequestBody, 'parentId'> = {
...body,
cognitoCredentials: exactCredentials,
}
const response = await this.post(path, filteredBody)
if (!responseIsSuccessful(response)) {
return await this.throw(response, 'openProjectBackendError', title)
return this.throw(response, 'openProjectBackendError', title)
} else {
return
}
}
}
/** Update the name or AMI of a project.
* @throws An error if a non-successful status code (not 200-299) was received. */

View File

@ -93,6 +93,7 @@
"closeProjectBackendError": "Could not close project '$0'.",
"getProjectDetailsBackendError": "Could not get details of project '$0'.",
"openProjectBackendError": "Could not open project '$0'.",
"openProjectMissingCredentialsBackendError": "Could not open project '$0': Missing credentials.",
"updateProjectBackendError": "Could not update project '$0'.",
"checkResourcesBackendError": "Could not get resource usage for project '$0'.",
"listFilesBackendError": "Could not list files.",

View File

@ -69,6 +69,7 @@ interface PlaceholderOverrides {
readonly closeProjectBackendError: [string]
readonly getProjectDetailsBackendError: [string]
readonly openProjectBackendError: [string]
readonly openProjectMissingCredentialsBackendError: [string]
readonly updateProjectBackendError: [string]
readonly checkResourcesBackendError: [string]
readonly uploadFileWithNameBackendError: [string]