Skip to content

Commit 004f72f

Browse files
committed
Implemented already completed auth upgrade
1 parent c2d0c8a commit 004f72f

7 files changed

Lines changed: 375 additions & 258 deletions

File tree

package-lock.json

Lines changed: 242 additions & 182 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"homepage": "https://github.com/solid/solid-ui",
5555
"dependencies": {
5656
"@babel/runtime": "^7.14.0",
57+
"@inrupt/solid-client-authn-browser": "^1.10.1",
5758
"crypto-browserify": "^3.12.0",
5859
"escape-html": "^1.0.3",
5960
"jss": "^10.6.0",
@@ -63,7 +64,6 @@
6364
"path-browserify": "^1.0.1",
6465
"postcss-flexbugs-fixes": "^5.0.2",
6566
"rdflib": "^2.2.6",
66-
"solid-auth-client": "^2.5.6",
6767
"solid-logic": "^1.3.6",
6868
"solid-namespace": "^0.5.1",
6969
"stream-browserify": "^3.0.0",

src/authn/authSession.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {
2+
Session,
3+
getClientAuthenticationWithDependencies
4+
} from '@inrupt/solid-client-authn-browser'
5+
6+
let authSession
7+
// @ts-ignore
8+
if (!window.authSession) {
9+
authSession = new Session(
10+
{
11+
clientAuthentication: getClientAuthenticationWithDependencies({})
12+
},
13+
'mySession'
14+
)
15+
// @ts-ignore
16+
window.authSession = authSession
17+
} else {
18+
// @ts-ignore
19+
authSession = window.authSession
20+
}
21+
22+
export default authSession

src/authn/authn.ts

Lines changed: 90 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020
* @packageDocumentation
2121
*/
2222
import { graph, namedNode, NamedNode, Namespace, serialize, st, Statement, sym, BlankNode } from 'rdflib'
23-
import solidAuthClient from 'solid-auth-client'
2423
import { PaneDefinition } from 'pane-registry'
2524
import { Signup } from './signup'
2625
import * as widgets from '../widgets'
2726
import * as ns from '../ns.js'
2827
import * as utils from '../utils'
2928
import { alert } from '../log'
29+
import authSession from './authSession'
3030
import { AppDetails, AuthenticationContext } from './types'
3131
import * as debug from '../debug'
3232
import { textInputStyle, buttonStyle, commentStyle } from '../style'
@@ -35,7 +35,7 @@ import { Quad_Object } from 'rdflib/lib/tf-types'
3535
import { solidLogicSingleton } from '../logic'
3636
import { CrossOriginForbiddenError, FetchError, NotFoundError, SameOriginForbiddenError, UnauthorizedError, ACL_LINK } from 'solid-logic'
3737

38-
export { solidAuthClient }
38+
export { authSession }
3939

4040
// const userCheckSite = 'https://databox.me/'
4141

@@ -97,13 +97,8 @@ export function defaultTestUser (): NamedNode | null {
9797
* @returns Named Node or null
9898
*/
9999
export function currentUser (): NamedNode | null {
100-
const str = localStorage['solid-auth-client']
101-
if (str) {
102-
const da = JSON.parse(str)
103-
if (da.session && da.session.webId) {
104-
// @@ TODO check has not expired
105-
return sym(da.session.webId)
106-
}
100+
if (authSession.info.webId) {
101+
return sym(authSession.info.webId)
107102
}
108103
return offlineTestID() // null unless testing
109104
// JSON.parse(localStorage['solid-auth-client']).session.webId
@@ -846,11 +841,10 @@ function signInOrSignUpBox (
846841
signInPopUpButton.setAttribute('value', 'Log in')
847842
signInPopUpButton.setAttribute('style', `${signInButtonStyle}background-color: #eef;`)
848843

849-
signInPopUpButton.addEventListener('click', () => {
850-
const offline = offlineTestID()
851-
if (offline) return setUserCallback(offline.uri)
852-
return solidAuthClient.popupLogin().then(session => {
853-
const webIdURI = session.webId
844+
authSession.onLogin(() => {
845+
const sessionInfo = authSession.info
846+
if (sessionInfo && sessionInfo.isLoggedIn) {
847+
const webIdURI = sessionInfo.webId
854848
// setUserCallback(webIdURI)
855849
const divs = dom.getElementsByClassName(magicClassName)
856850
debug.log(`Logged in, ${divs.length} panels to be serviced`)
@@ -871,6 +865,23 @@ function signInOrSignUpBox (
871865
}
872866
}
873867
}
868+
}
869+
})
870+
871+
signInPopUpButton.addEventListener('click', () => {
872+
const offline = offlineTestID()
873+
if (offline) return setUserCallback(offline.uri)
874+
875+
const thisUrl = new URL(window.location.href).origin
876+
// HACK solid-client-authn-js no longer comes with its own UI for selecting
877+
// an IDP. This was the easiest way to get the user to select.
878+
// TODO: make a nice UI to select an IDP
879+
const issuer = prompt('Enter an issuer', thisUrl)
880+
authSession.login({
881+
// @ts-ignore this library requires a specific kind of URL that isn't global
882+
redirectUrl: window.location.href,
883+
// @ts-ignore
884+
oidcIssuer: issuer
874885
})
875886
}, false)
876887

@@ -894,8 +905,8 @@ function signInOrSignUpBox (
894905
/**
895906
* @returns {Promise<string|null>} Resolves with WebID URI or null
896907
*/
897-
function webIdFromSession (session?: { webId: string }): string | null {
898-
const webId = session ? session.webId : null
908+
function webIdFromSession (session?: { webId?: string }): string | null {
909+
const webId = session?.webId ? session.webId : null
899910
if (webId) {
900911
saveUser(webId)
901912
}
@@ -912,42 +923,59 @@ function checkCurrentUser () {
912923
}
913924
*/
914925

926+
// HACK this global variable exists to prevent authSession.handleIncomingRedirect
927+
// From being called twice. It would not be needed if it automatically redirected
928+
// by iteself. See https://github.com/inrupt/solid-client-authn-js/issues/514
929+
let checkingRedirect = false
930+
915931
/**
916932
* Retrieves currently logged in webId from either
917-
* defaultTestUser or SolidAuthClient
933+
* defaultTestUser or SolidAuth
918934
* @param [setUserCallback] Optional callback
919935
*
920936
* @returns Resolves with webId uri, if no callback provided
921937
*/
922-
export function checkUser<T> (
938+
export async function checkUser<T> (
923939
setUserCallback?: (me: NamedNode | null) => T
924-
): Promise<NamedNode | T> {
940+
): Promise<NamedNode | T | null> {
941+
/**
942+
* Handle a successful authentication redirect
943+
*/
944+
// HACK normally you wouldn't need to do a check to see if 'code' is in the
945+
// query, but it was removed from solid-client-authn-js
946+
// See https://github.com/inrupt/solid-client-authn-js/issues/421
947+
// Remove this after
948+
const authCode = new URL(window.location.href).searchParams.get('code')
949+
if (authCode && !checkingRedirect) {
950+
checkingRedirect = true
951+
// Being redirected after requesting a token
952+
await authSession
953+
.handleIncomingRedirect(window.location.href)
954+
// HACK solid-client-authn-js should automatically remove code and state
955+
// from the URL, but it doesn't, so we do it manually here
956+
// see https://github.com/inrupt/solid-client-authn-js/issues/514
957+
const newPageUrl = new URL(window.location.href)
958+
newPageUrl.searchParams.delete('code')
959+
newPageUrl.searchParams.delete('state')
960+
window.history.replaceState({}, '', newPageUrl.toString())
961+
}
962+
925963
// Check to see if already logged in / have the WebID
926-
const me = defaultTestUser()
964+
let me = defaultTestUser()
927965
if (me) {
928966
return Promise.resolve(setUserCallback ? setUserCallback(me) : me)
929967
}
930968

931969
// doc = solidLogicSingleton.store.any(doc, ns.link('userMirror')) || doc
970+
const webId = webIdFromSession(authSession.info)
932971

933-
return solidAuthClient
934-
.currentSession()
935-
.then(webIdFromSession)
936-
.catch(err => {
937-
debug.log('Error fetching currentSession:', err)
938-
})
939-
.then(webId => {
940-
// if (webId.startsWith('dns:')) { // legacy rww.io pseudo-users
941-
// webId = null
942-
// }
943-
const me = saveUser(webId)
972+
me = saveUser(webId)
944973

945-
if (me) {
946-
debug.log(`(Logged in as ${me} by authentication)`)
947-
}
974+
if (me) {
975+
debug.log(`(Logged in as ${me} by authentication)`)
976+
}
948977

949-
return setUserCallback ? setUserCallback(me) : me
950-
})
978+
return Promise.resolve(setUserCallback ? setUserCallback(me) : me)
951979
}
952980

953981
/**
@@ -986,7 +1014,7 @@ export function loginStatusBox (
9861014

9871015
function logoutButtonHandler (_event) {
9881016
// UI.preferences.set('me', '')
989-
solidAuthClient.logout().then(
1017+
authSession.logout().then(
9901018
function () {
9911019
const message = `Your WebID was ${me}. It has been forgotten.`
9921020
me = null
@@ -1025,39 +1053,35 @@ export function loginStatusBox (
10251053
}
10261054

10271055
box.refresh = function () {
1028-
solidAuthClient.currentSession().then(
1029-
session => {
1030-
if (session && session.webId) { // offline
1031-
me = sym(session.webId)
1032-
} else {
1033-
me = offlineTestID() // null unless testing
1034-
}
1035-
if ((me && box.me !== me.uri) || (!me && box.me)) {
1036-
widgets.clearElement(box)
1037-
if (me) {
1038-
box.appendChild(logoutButton(me, options))
1039-
} else {
1040-
box.appendChild(signInOrSignUpBox(dom, setIt, options))
1041-
}
1042-
}
1043-
box.me = me ? me.uri : null
1044-
},
1045-
err => {
1046-
alert(`loginStatusBox: ${err}`)
1056+
const sessionInfo = authSession.info
1057+
if (sessionInfo && sessionInfo.webId) {
1058+
me = sym(sessionInfo.webId)
1059+
} else {
1060+
me = null
1061+
}
1062+
if ((me && box.me !== me.uri) || (!me && box.me)) {
1063+
widgets.clearElement(box)
1064+
if (me) {
1065+
box.appendChild(logoutButton(me, options))
1066+
} else {
1067+
box.appendChild(signInOrSignUpBox(dom, setIt, options))
10471068
}
1048-
)
1069+
}
1070+
box.me = me ? me.uri : null
10491071
}
10501072

1051-
if (solidAuthClient.trackSession) {
1052-
solidAuthClient.trackSession(session => {
1053-
if (session && session.webId) {
1054-
me = sym(session.webId)
1055-
} else {
1056-
me = null
1057-
}
1058-
box.refresh()
1059-
})
1073+
function trackSession () {
1074+
const sessionInfo = authSession.info
1075+
if (sessionInfo && sessionInfo.webId) {
1076+
me = sym(sessionInfo.webId)
1077+
} else {
1078+
me = null
1079+
}
1080+
box.refresh()
10601081
}
1082+
trackSession()
1083+
authSession.onLogin(trackSession)
1084+
authSession.onLogout(trackSession)
10611085

10621086
box.me = '99999' // Force refresh
10631087
box.refresh()

src/authn/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
selectWorkspace,
2525
setACLUserPublic,
2626
saveUser,
27-
solidAuthClient
27+
authSession
2828
} from './authn'
2929

3030
export const authn = {
@@ -48,5 +48,5 @@ export const authn = {
4848
selectWorkspace,
4949
setACLUserPublic,
5050
saveUser,
51-
solidAuthClient
51+
authSession
5252
}

src/header/index.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
work in solid-ui by adjusting where imported functions are found.
55
*/
66
import { IndexedFormula, NamedNode, sym } from 'rdflib'
7-
import { loginStatusBox, solidAuthClient } from '../authn/authn'
7+
import { loginStatusBox, authSession } from '../authn/authn'
88
import * as widgets from '../widgets'
99
import { emptyProfile } from './empty-profile'
1010
import { addStyleClassToElement, getPod, throttle } from './headerHelpers'
@@ -76,14 +76,17 @@ export async function initHeader (store: IndexedFormula, options?: HeaderOptions
7676
}
7777

7878
const pod = getPod()
79-
solidAuthClient.trackSession(rebuildHeader(header, store, pod, options))
79+
rebuildHeader(header, store, pod, options)()
80+
authSession.onLogout(rebuildHeader(header, store, pod, options))
81+
authSession.onLogin(rebuildHeader(header, store, pod, options))
8082
}
8183
/**
8284
* @ignore exporting this only for the unit test
8385
*/
8486
export function rebuildHeader (header: HTMLElement, store: IndexedFormula, pod: NamedNode, options?: HeaderOptions) {
85-
return async (session: SolidSession | null) => {
86-
const user = session ? sym(session.webId) : null
87+
return async () => {
88+
const sessionInfo = authSession.info
89+
const user = sessionInfo.webId ? sym(sessionInfo.webId) : null
8790
header.innerHTML = ''
8891
header.appendChild(await createBanner(store, pod, user, options))
8992
}
@@ -168,7 +171,7 @@ export async function createUserMenu (store: IndexedFormula, user: NamedNode, op
168171
}
169172
}
170173

171-
loggedInMenuList.appendChild(createUserMenuItem(createUserMenuButton('Log out', () => solidAuthClient.logout())))
174+
loggedInMenuList.appendChild(createUserMenuItem(createUserMenuButton('Log out', () => authSession.logout())))
172175

173176
const loggedInMenu = document.createElement('nav')
174177

src/logic.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,18 @@
22
//
33

44
import * as debug from './debug'
5-
import auth from 'solid-auth-client'
5+
import authSession from './authn/authSession'
66
import { SolidLogic } from 'solid-logic'
77

8-
export const solidLogicSingleton = new SolidLogic({ fetch: auth.fetch }, auth)
8+
const fetcher = async (url, requestInit) => {
9+
if (authSession.info.webId) {
10+
return authSession.fetch(url, requestInit)
11+
} else {
12+
return window.fetch(url, requestInit)
13+
}
14+
}
15+
16+
export const solidLogicSingleton = new SolidLogic({ fetch: fetcher }, authSession)
917

1018
// Make this directly accessible as it is what you need most of the time
1119
export const store = solidLogicSingleton.store

0 commit comments

Comments
 (0)