Skip to content
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

Add code documentation to new extension #46

Open
wants to merge 8 commits into
base: extension-as-remote
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
module.exports = {
root: true,
env: {browser: true, es2020: true, webextensions: true},
extends: [
'eslint:recommended'
],
ignorePatterns: ['dist', '.eslintrc.cjs', 'webpack.*'],
parserOptions: {ecmaVersion: 'latest', sourceType: 'module'},
settings: {react: {version: '18.2'}},
plugins: ['jsdoc'],
rules: {
'prefer-const': ['error', {
'destructuring': 'any',
'ignoreReadBeforeAssign': false
}],
'no-multiple-empty-lines': ['error',
{'max': 1, 'maxEOF': 0}
],
'indent': ['error', 2],
'semi': ['error', 'always'],
'camelcase': 'error',
'quotes': ['error', 'single', { 'avoidEscape': true }],
'jsdoc/check-access': 1, // Recommended
'jsdoc/check-alignment': 1, // Recommended
// 'jsdoc/check-examples': 1,
// 'jsdoc/check-indentation': 1,
// 'jsdoc/check-line-alignment': 1,
'jsdoc/check-param-names': 1, // Recommended
'jsdoc/check-property-names': 1, // Recommended
// 'jsdoc/check-syntax': 1,
'jsdoc/check-tag-names': 1, // Recommended
'jsdoc/check-types': 1, // Recommended
'jsdoc/check-values': 1, // Recommended
'jsdoc/empty-tags': 1, // Recommended
'jsdoc/implements-on-classes': 1, // Recommended
// 'jsdoc/informative-docs': 1,
// 'jsdoc/match-description': 1,
'jsdoc/multiline-blocks': 1, // Recommended
// 'jsdoc/no-bad-blocks': 1,
// 'jsdoc/no-blank-block-descriptions': 1,
// 'jsdoc/no-defaults': 1,
// 'jsdoc/no-missing-syntax': 1,
'jsdoc/no-multi-asterisks': 1, // Recommended
// 'jsdoc/no-restricted-syntax': 1,
// 'jsdoc/no-types': 1,
'jsdoc/no-undefined-types': 1, // Recommended
// 'jsdoc/require-asterisk-prefix': 1,
'jsdoc/require-description': 1,
'jsdoc/require-description-complete-sentence': 1,
// 'jsdoc/require-example': 1,
// 'jsdoc/require-file-overview': 1,
// 'jsdoc/require-hyphen-before-param-description': 1,
'jsdoc/require-jsdoc': 1, // Recommended
'jsdoc/require-param': 1, // Recommended
'jsdoc/require-param-description': 1, // Recommended
'jsdoc/require-param-name': 1, // Recommended
'jsdoc/require-param-type': 1, // Recommended
'jsdoc/require-property': 1, // Recommended
'jsdoc/require-property-description': 1, // Recommended
'jsdoc/require-property-name': 1, // Recommended
'jsdoc/require-property-type': 1, // Recommended
'jsdoc/require-returns': 1, // Recommended
'jsdoc/require-returns-check': 1, // Recommended
'jsdoc/require-returns-description': 1, // Recommended
'jsdoc/require-returns-type': 1, // Recommended
// 'jsdoc/require-throws': 1,
'jsdoc/require-yields': 1, // Recommended
'jsdoc/require-yields-check': 1, // Recommended
// 'jsdoc/sort-tags': 1,
'jsdoc/tag-lines': 1, // Recommended
'jsdoc/valid-types': 1 // Recommended
},
}
15 changes: 0 additions & 15 deletions .eslintrc.json

This file was deleted.

38 changes: 38 additions & 0 deletions .markdownlint-cli2.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"use strict";

module.exports = {
ignores: [ "node_modules/", "LICENSE.md", ".github/", "showcase-app", "examples" ],

globs: [ "**/*.md" ],

config: {
// Enable all markdownlint rules
default: true,

MD004: {
"style": "dash"
},

// Set list indent level to 2
MD007: { "indent": 2 },

// Enable line length check but exclude tables and code blocks
MD013: {
line_length: 120,
tables: false,
code_blocks: false
},

// Allow multiple subheadings with the same content
// across different section (#1 ##A ##B #2 ##A ##B)
MD024: {
allow_different_nesting: true
},

// Set Ordered list item prefix to "ordered" (use 1. 2. 3. not 1. 1. 1.)
MD029: { "style": "ordered" },

// Allow inline HTML
MD033: false,
}
};
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## Unreleased

### Added

- Development environment information
- Package instructions
- Add instructions in README where people can find signed extension (see [issue 22](https://github.com/KNowledgeOnWebScale/solid-authentication-browser-extension/issues/22))
Expand All @@ -17,10 +18,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Add form validation (see [issue 35](https://github.com/KNowledgeOnWebScale/solid-authentication-browser-extension/issues/35))

### Changed

- Update development instructions
- Only authenticate requests that return 401 unauthorized (see [issue 10](https://github.com/KNowledgeOnWebScale/solid-authentication-browser-extension/issues/10))

### Fixed

- Fix a bug that caused the popup to still show login options and throw an error after already being logged in
- Fix a bug that caused the status of the enable regex button te be out of sync after login when reopening the popup
- Fix a bug that caused the status of the enable regex button to not be 'off' by default after logout
Expand All @@ -29,4 +32,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## 1.0.0 - 2023-03-17

- First version!
- First version!
151 changes: 132 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,53 @@
# Solid Identity Extension

This Chrome extension acts as a remote control to **manage your Solid identities** and make it easy for the user to switch between their WebIDs.
The way this works is by giving the user the option to add _profiles_ to the extension which it will store to persist over the course of its use.
A profile describes either a WebID or an IDP. Subsequently the profile gets a display name and a color to generate an avatar used to distinguish between other profiles.
Profiles will be listed when clicking on the extension, and an active profile is shown in the top.

The extension provides an API to a Solid app either through the use of `chrome.runtime.connect` with the extension ID, or by using a plugin provided by us as an NPM package to make interfacing with the extension.
A draft of how this package would work can be found in `./showcase-app/plugin/`. The idea is for the **Solid app (not part of the extension) to manage the authentication**, and the extension **only provides a way of keeping track of profiles**.
Previous versions of this extension intercepted or modified network requests, and due to security concerns, this was not desirable.
This Chrome extension currently acts as a remote control to **manage your Solid identities** and
make it easy for the user to switch between their WebIDs.
The way this works is by giving the user the option to add _profiles_ to the extension which
it will store to persist over the course of its use.
A profile describes either a WebID or an IDP.
Subsequently, the profile gets a display name and
a color to generate an avatar used to distinguish between other profiles.
Profiles will be listed when clicking on the extension, and
an active profile is shown in the top.

The extension provides an API to a Solid app either through the use of `chrome.runtime.connect` with the extension ID, or
by using a plugin provided by us as an NPM package to make interfacing with the extension. (TODO)
A draft of how this package would work can be found in `./showcase-app/plugin/`.
The idea is for the **Solid app (not part of the extension) to manage the authentication**, and
the extension **only provides a way of keeping track of profiles**.
Previous versions of this extension intercepted or modified network requests, and
due to security concerns, this was not desirable.

## Quickstart

The extension was developed using `node:lts/hydrogen`. You can use `nvm` to synchronise this for local development.
The extension was developed using `node:lts/hydrogen`.
You can use `nvm` to synchronise this for local development.

```
```shell
npm i
npm start
```

This will start up the build-process with hot-reload.

To add the extension to the browser, navigate to `chrome://extensions/` and click `Load unpacked`. Navigate and add the `dist/` folder of this project.
To add the extension to the browser, navigate to `chrome://extensions/` and click `Load unpacked`.
Navigate and add the `dist/` folder of this project.

Hot-reloading replenishes the files every time you save something in `src/`. In some cases, mainly when errors occur, you must reload the module in the `chrome://extensions/`. It should not be removed. You may pin the extension for convenience.
Hot-reloading replenishes the files every time you save something in `src/`.
In some cases, mainly when errors occur, you must reload the module in the `chrome://extensions/`.
It should not be removed. You may pin the extension for convenience.

Use the `showcase-app` if you want to try out an example Solid app to test this extension end-to-end.

```
```shell
cd `./showcase-app`
yarn install
yarn start
```

Navigate to `http://localhost:5173/`. When the extension is present and has identities, the option will be shown to continue as the active set profile.
Navigate to `http://localhost:5173/`.
When the extension is present and has identities,
the option will be shown to continue as the active set profile.

## Testing the flow

Expand All @@ -41,16 +56,114 @@ In order to full test how this extension works end-to-end, you must take the fol
- Follow the steps in [quickstart](#quickstart) to run the extension and the showcase app
- Open the extension and **add a new profile** if you haven't already
- A dialog appears in which you can give the new profile a display and color + add either an IDP or WebID
- Once created, the dialog and extension will close. When you open the extension again the profile will be in there and selected as active
- In the Solid showcase app running on `http://localhost:5173/` you will be find the login widget allows you to one-click sign-in with the active profile. If it is not present (it should), you can switch profile to trigger updates between the app and the extension.
- After clicking the one-click sign-in button, you will be redirected to the IDP where you must sign in and you will be able to authorize the WebID with the Solid showcase app.
- You may then use the logout button to prompt logging out. When you select another identity in the extension, you will be automatically logged out.
- Once created, the dialog and extension will close.
When you open the extension again the profile will be in there and selected as active.
- In the Solid showcase app running on `http://localhost:5173/` you find the login widget that
allows you to one-click sign-in with the active profile.
If it is not present (it should),
you can switch profile to trigger updates between the app and the extension.
- After clicking the one-click sign-in button,
you will be redirected to the IDP where you must sign in.
You will be able to authorize the WebID with the Solid showcase app.
- You may then use the logout button to prompt logging out.
When you select another identity in the extension,
you will be automatically logged out.

## Obtaining WebIDs for testing

You can create temporary WebIDs using `https://pod.playground.solidlab.be/idp/register/`. When creating a new profile you may add `https://pod.playground.solidlab.be` as the IDP, or the WebID you've obtained after registration.
You can create temporary WebIDs using `https://pod.playground.solidlab.be/idp/register/`.
When creating a new profile you may add `https://pod.playground.solidlab.be` as the IDP, or
the WebID you've obtained after registration.
These are reset daily, so make sure you've recreated it in order for authorization to work.

```mermaid
sequenceDiagram
actor user as User
participant extension as Solid Identity Manager
participant app1 as Solid App
participant browser as Browser
participant idp as Identity Provider

user ->> extension: Add new profile called "Profile A" (automatically becomes active profile)
user ->> browser: Browse to app
browser ->> app1: Open app
app1 ->> browser: Subscribe to data/changes from Solid Identity Manager
app1 ->> browser: Ask for active profile
browser ->> extension: Ask for active profile
extension -->> browser: Return Profile A
browser -->> app1: Return Profile A
app1 ->> app1: Show button to log in with Profile A
user ->> app1: Click on button
app1 ->> browser: Redirect user to IDP
browser ->> idp: Load login and consent page
user ->> browser: User logs in and gives consent
browser ->> idp: Send log-in and consent data to IDP
idp ->> browser: Redirect user to app
user ->> app1: See "Logged in" message
user ->> extension: Add new profile called "Profile B"
user ->> extension: Set "Profile B" as active profile
extension ->> browser: Notify subscribed apps about profile change
browser ->> app1: Notify about profile change
app1 ->> app1: Log out Profile A
app1 ->> app1: Show button to log in with Profile B
```

## Future work and ideas

Currently the extension acts as a remote control for managing profiles.
It can set an active identity, manage existing profiles and modify/delete them.
Profiles simply contain either an IDP or WebID, with an additional display name and color label.
Solid Apps can then get this profile data to effectively log in using these credentials.
There are some limitations in this setup.
We might have to change the way this extension works in order to cater to the needs of its users.

### Distinct profiles per tab

Different solid apps in different parallel tabs might want to use different profiles.
The current logic of having an active profile implies that every app will use the same identity,
which is not necessarily desired behaviour.

### Multiple options

To allow the above condition to be satisfied,
the showcase app in this bundle should allow the user to select which of the stored profiles
they want to use for this specific app in this specific tab.
It's more desirable to have list of available profiles to continue with.

### Session persistence where possible

It's very difficult to let the extension handle login/authorisation for the solid application for security reasons.
Technically this is also challenging because the environment the extension runs in is neither pure Browser nor NodeJS,
making usage of the existing inrupt package difficult and non-standard.
Storing sessions between page refreshes in separate tabs/apps would therefore
ideally be a concern for the solid app and not the extension.
The way the current setup makes this easier,
is by providing an intermediate layer in the form of a package developers can use.

### Ease of access

Ideally the extension solves the problem of convenience.
Having to enter WebIDs again and again everywhere,
especially when developing and testing out different cases with distinct WebIDs & pods.
It is convenient if you can just click and select which profile you'd like to go forward with per tab/app.
For security reasons of course,
first time use of a WebID in a certain app will ask for permissions you will explicitly have to grant.
Also, you will be prompted to sign in with your IDP every time,
but autofill already solves part of that specific inconvenience.

### Multi-session across multiple tabs running the same application

Depending on which app you use, this is possible or not.
An example of an app where this is not possible, is <https://podpro.dev/>.
The documentation at inrupt describes that Session data is actually not stored anywhere clientside, and
every refresh the IDP is consulted to validate the running session.
When you have two tabs with the same app,
it might actually not be possible or easy to have the two sessions in parallel.
Because when you log into another WebID in the other tab, and
refresh the first tab, it will effectively retrieve the latest session.
Storing sessions or tokens in localstorage or anywhere clientside is discouraged for security reasons.
Perhaps with additional research, a workaround can be conceptualized that does not compromise security.

## License

This code is copyrighted by [Ghent University – imec](http://idlab.ugent.be/) and
Expand Down
Loading