Skip to content

Commit

Permalink
Add Solid authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
NoelDeMartin committed Oct 11, 2018
1 parent e0e6074 commit d3d0047
Show file tree
Hide file tree
Showing 13 changed files with 2,983 additions and 804 deletions.
3,510 changes: 2,746 additions & 764 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Expand Up @@ -9,12 +9,15 @@
},
"dependencies": {
"register-service-worker": "^1.0.0",
"solid-auth-client": "^2.2.6",
"tailwindcss": "^0.6.6",
"vue": "^2.5.17",
"vuetify": "^1.2.8"
},
"devDependencies": {
"@babel/polyfill": "^7.0.0",
"@types/node": "^10.11.7",
"@types/webpack-env": "^1.13.6",
"@vue/cli-plugin-babel": "^3.0.0",
"@vue/cli-plugin-eslint": "^3.0.0",
"@vue/cli-plugin-pwa": "^3.0.0",
Expand Down
53 changes: 19 additions & 34 deletions src/App.vue
@@ -1,50 +1,35 @@
<template>
<v-app>
<div class="bg-background w-screen h-screen flex flex-col items-center justify-center">
<h1 class="text-4xl">Focus 省</h1>
<v-form class="w-4/5" @submit.prevent="createTask">
<div class="flex">
<v-text-field v-model="newTask" />
<v-btn color="primary" @click="createTask">Add</v-btn>
</div>
</v-form>
<v-list class="w-4/5">
<template v-for="(task, index) of tasks">
<v-list-tile :key="index">
{{ task }}
</v-list-tile>
<v-divider v-if="index !== tasks.length -1" :key="`divider-${index}`" />
</template>
<v-list-tile v-if="tasks.length === 0" class="text-grey-darker">
No tasks
</v-list-tile>
</v-list>
</div>
<Splash v-if="loading"/>
<Home v-else-if="$auth.loggedIn" />
<Login v-else />
</v-app>
</template>

<script lang="ts">
import Vue from 'vue';
interface ComponentData {
newTask: string;
tasks: string[];
}
import Home from '@/pages/Home.vue';
import Login from '@/pages/Login.vue';
import Splash from '@/pages/Splash.vue';
export default Vue.extend({
data(): ComponentData {
components: {
Home,
Login,
Splash,
},
data() {
return {
newTask: '',
tasks: [],
loading: true,
};
},
methods: {
createTask() {
if (this.newTask) {
this.tasks.push(this.newTask);
this.newTask = '';
}
},
mounted() {
this.$auth
.init()
.then(() => {
this.loading = false;
});
},
});
</script>
Expand Down
10 changes: 7 additions & 3 deletions src/main.ts
@@ -1,12 +1,16 @@
import Vue from 'vue';

import App from './App.vue';
import App from '@/App.vue';

import './plugins/vuetify';
import './plugins/registerServiceWorker';
import Auth from '@/services/Auth';

import '@/plugins/vuetify';
import '@/plugins/registerServiceWorker';

Vue.config.productionTip = false;

Vue.prototype.$auth = Auth;

new Vue({
render: h => h(App),
}).$mount('#app');
51 changes: 51 additions & 0 deletions src/pages/Home.vue
@@ -0,0 +1,51 @@
<template>
<div class="bg-background w-screen h-screen flex flex-col items-center justify-center">
<div class="fixed pin-r pin-t m-4">
<a @click="$auth.logout()">Logout</a>
</div>
<h1 class="text-4xl">Focus 省</h1>
<v-form class="w-4/5" @submit.prevent="createTask">
<div class="flex">
<v-text-field v-model="newTask" />
<v-btn color="primary" @click="createTask">Add</v-btn>
</div>
</v-form>
<v-list class="w-4/5">
<template v-for="(task, index) of tasks">
<v-list-tile :key="index">
{{ task }}
</v-list-tile>
<v-divider v-if="index !== tasks.length -1" :key="`divider-${index}`" />
</template>
<v-list-tile v-if="tasks.length === 0" class="text-grey-darker">
No tasks
</v-list-tile>
</v-list>
</div>
</template>

<script lang="ts">
import Vue from 'vue';
interface ComponentData {
newTask: string;
tasks: string[];
}
export default Vue.extend({
data(): ComponentData {
return {
newTask: '',
tasks: [],
};
},
methods: {
createTask() {
if (this.newTask) {
this.tasks.push(this.newTask);
this.newTask = '';
}
},
},
});
</script>
30 changes: 30 additions & 0 deletions src/pages/Login.vue
@@ -0,0 +1,30 @@
<template>
<div class="bg-background w-screen h-screen flex flex-col items-center justify-center">
<h1 class="text-4xl">Focus 省</h1>
<v-form class="w-4/5" @submit.prevent="login">
<div class="flex">
<v-text-field v-model="idp" />
<v-btn color="primary" @click="login">Login</v-btn>
</div>
</v-form>
</div>
</template>

<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
data() {
return {
idp: '',
};
},
methods: {
login() {
// TODO show loading
// TODO handle errors
this.$auth.login(this.idp);
},
},
});
</script>
10 changes: 10 additions & 0 deletions src/pages/Splash.vue
@@ -0,0 +1,10 @@
<template>
<div class="bg-background w-screen h-screen flex flex-col items-center justify-center">
<h1>Loading...</h1>
</div>
</template>

<script>
export default {
};
</script>
51 changes: 51 additions & 0 deletions src/services/Auth.ts
@@ -0,0 +1,51 @@
import SolidAuthClient from 'solid-auth-client';

import Reactive from '@/utils/Reactive';

interface Data {
webId: string | null;
idp: string | null;
}

class Auth {

private data: Data = Reactive.object({
webId: null,
idp: null,
});

public get loggedIn(): boolean {
return this.data.webId !== null;
}

public get webId(): string {
return this.data.webId as string;
}

public get idp(): string {
return this.data.idp as string;
}

public async init(): Promise<void> {
return SolidAuthClient.trackSession(session => {
if (session) {
this.data.webId = session.webId;
this.data.idp = session.idp;
} else {
this.data.webId = null;
this.data.idp = null;
}
});
}

public async login(idp: string): Promise<void> {
await SolidAuthClient.login(idp);
}

public async logout(): Promise<void> {
await SolidAuthClient.logout();
}

}

export default new Auth();
39 changes: 39 additions & 0 deletions src/types/solid-auth-client.d.ts
@@ -0,0 +1,39 @@
declare module 'solid-auth-client' {

import { EventEmitter } from 'events';

type AsyncStorage = any;

type loginOptions = {
callbackUri?: string,
popupUri?: string,
storage?: AsyncStorage,
};

type Session = {
idp: string,
webId: string,
accessToken: string,
idToken: string,
clientId: string,
sessionKey: string,
};

class SolidAuthClient extends EventEmitter {
public fetch(input: RequestInfo, options?: Object): Promise<Response>;

public login(idp: string, options?: loginOptions): Promise<Session | void>;

public popupLogin(options: loginOptions): Promise<Session | void>;

public currentSession(storage?: AsyncStorage): Promise<Session | void>;

public trackSession(callback: (session?: Session) => void): Promise<void>;

public logout(storage?: AsyncStorage): Promise<void>;
}

const auth: SolidAuthClient;

export default auth;
}
7 changes: 7 additions & 0 deletions src/types/vue.d.ts
@@ -0,0 +1,7 @@
import Auth from '@/services/Auth';

declare module 'vue/types/vue' {
interface Vue {
$auth: typeof Auth;
}
}
9 changes: 9 additions & 0 deletions src/utils/Reactive.ts
@@ -0,0 +1,9 @@
import Vue from 'vue';

export default class Reactive {

public static object<T>(data: T): T {
return new Vue({ data });
}

}
3 changes: 0 additions & 3 deletions tsconfig.json
Expand Up @@ -10,9 +10,6 @@
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
Expand Down
11 changes: 11 additions & 0 deletions vue.config.js
@@ -0,0 +1,11 @@
module.exports = {
configureWebpack: {
externals: {
'node-fetch': 'fetch',
'text-encoding': 'TextEncoder',
'whatwg-url': 'window',
'isomorphic-fetch': 'fetch',
'@trust/webcrypto': 'crypto'
},
},
};

0 comments on commit d3d0047

Please sign in to comment.