diff --git a/src/login/login.ts b/src/login/login.ts index f69f8206..c37d4224 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -126,6 +126,12 @@ export async function ensureLoadedPreferences ( try { context = await ensureLoadedProfile(context) + if (!context.me || !context.publicProfile) { + context.preferencesFileError = + context.preferencesFileError || 'Not logged in, so preferences were not loaded.' + return context + } + // console.log('back in Solid UI after logInLoadProfile', context) const preferencesFile = await loadPreferences(context.me as NamedNode) if (progressDisplay) { @@ -134,10 +140,13 @@ export async function ensureLoadedPreferences ( context.preferencesFile = preferencesFile } catch (err) { let m2: string - if (err instanceof UnauthorizedError) { + const errorMessage = err instanceof Error ? err.message : `${err}` + if (err instanceof UnauthorizedError || /(?:status:\s*401\b|unauthorized)/i.test(errorMessage)) { m2 = - 'Oops — you are not authenticated (properly logged in), so SolidOS cannot read your preferences file. Try logging out and then logging back in.' - alert(m2) + 'Not logged in, so preferences were not loaded.' + context.preferencesFileError = m2 + debug.warn(m2) + return context } else if (err instanceof CrossOriginForbiddenError) { m2 = `Unauthorized: Assuming preference file blocked for origin ${window.location.origin}` context.preferencesFileError = m2 @@ -145,16 +154,19 @@ export async function ensureLoadedPreferences ( } else if (err instanceof SameOriginForbiddenError) { m2 = 'You are not authorized to read your preference file. This may be because you are using an untrusted web app.' + context.preferencesFileError = m2 debug.warn(m2) return context } else if (err instanceof NotEditableError) { m2 = 'You are not authorized to edit your preference file. This may be because you are using an untrusted web app.' + context.preferencesFileError = m2 debug.warn(m2) return context } else if (err instanceof WebOperationError) { m2 = 'You are not authorized to edit your preference file. This may be because you are using an untrusted web app.' + context.preferencesFileError = m2 debug.warn(m2) } else if (err instanceof FetchError) { m2 = `Strange: Error ${err.status} trying to read your preference file.${err.message}` @@ -177,20 +189,66 @@ export async function ensureLoadedPreferences ( export async function ensureLoadedProfile ( context: AuthenticationContext ): Promise { + const handleNotLoggedInProfile = (logMessage: (message: string) => void) => { + const notLoggedInMessage = 'Not logged in, so profile was not loaded.' + const notLoggedInMessageKey = 'not-logged-in-profile' + logMessage(notLoggedInMessage) + if (context.div && context.dom) { + const existingMessage = context.div.querySelector( + `[data-login-message="${notLoggedInMessageKey}"]` + ) + if (!existingMessage) { + const errorBlock = widgets.errorMessageBlock(context.dom, notLoggedInMessage, 'white') + errorBlock.setAttribute('data-login-message', notLoggedInMessageKey) + context.div.appendChild(errorBlock) + } + } + return context + } + if (context.publicProfile) { return context } // already done + let logInContext: AuthenticationContext | undefined try { - const logInContext = await ensureLoggedIn(context) + logInContext = await ensureLoggedIn(context) + if (!logInContext.me) { + const webId = authSession.info?.webId || await authn.checkUser() + if (webId) { + authn.saveUser(webId, logInContext) + } + } if (!logInContext.me) { - throw new Error('Could not log in') + return handleNotLoggedInProfile(debug.log) } context.publicProfile = await loadProfile(logInContext.me) } catch (err) { + const message = err instanceof Error ? err.message : `${err}` + if (err instanceof UnauthorizedError || /(status:\s*401\b|unauthorized)/i.test(message)) { + return handleNotLoggedInProfile(debug.warn) + } + const loggedInUser = logInContext && logInContext.me + const isNonFatalProfileSideLoadFailure = + !!loggedInUser && + ( + err instanceof CrossOriginForbiddenError || + err instanceof SameOriginForbiddenError || + /status:\s*403\b|forbidden/i.test(message) || + /cancel/i.test(message) + ) + if (isNonFatalProfileSideLoadFailure) { + debug.warn(`Unable to load all profile-linked resources; continuing as logged in user: ${message}`) + context.publicProfile = loggedInUser!.doc() + return context + } if (context.div && context.dom) { - context.div.appendChild(widgets.errorMessageBlock(context.dom, err.message)) + context.div.appendChild(widgets.errorMessageBlock(context.dom, message)) + } + const loginError = new Error(`Can't log in: ${message}`) as Error & { cause?: unknown } + if (err instanceof Error) { + loginError.cause = err } - throw new Error(`Can't log in: ${err}`) + throw loginError } return context } @@ -784,6 +842,13 @@ export function selectWorkspace ( function displayOptions (context) { // console.log('displayOptions!', context) + if (!context.preferencesFile) { + say( + context.preferencesFileError || 'Preferences not available.' + ) + return + } + async function makeNewWorkspace (_event) { const row = table.appendChild(dom.createElement('tr')) const cell = row.appendChild(dom.createElement('td')) @@ -1047,11 +1112,11 @@ export function newAppInstance ( * and/or a developer */ export async function getUserRoles (): Promise> { - const sessionInfo = authSession.info + const sessionInfo = authSession.info if (!sessionInfo?.isLoggedIn || !sessionInfo?.webId) { return [] } - + const currentUser = authn.currentUser() if (!currentUser) { return []