Auth and access codes work

the first half of #1
This commit is contained in:
Daniel J. Summers 2020-09-07 15:27:33 -04:00
parent 603754fdfb
commit 10658b0d77
10 changed files with 234 additions and 11 deletions

View File

@ -21,3 +21,6 @@ pnpm-debug.log*
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
dev-client.txt
src/auth/config.ts

View File

@ -11675,6 +11675,11 @@
} }
} }
}, },
"vue-router": {
"version": "4.0.0-beta.9",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.0-beta.9.tgz",
"integrity": "sha512-k8AGMm3LCTqnsEuF37AD4kcZVMwtnFEzdjACgmIII/xbLnTj3+o5XyH/zREBZutgv5q2hzlLltMVglqDQYMd/A=="
},
"vue-style-loader": { "vue-style-loader": {
"version": "4.1.2", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz", "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz",

View File

@ -3,20 +3,22 @@
"version": "0.8.0", "version": "0.8.0",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve --port 3005",
"build": "vue-cli-service build", "build": "vue-cli-service build --modern",
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"
}, },
"dependencies": { "dependencies": {
"core-js": "^3.6.5", "core-js": "^3.6.5",
"vue": "^3.0.0-0", "vue": "^3.0.0-0",
"vue-class-component": "^8.0.0-0" "vue-class-component": "^8.0.0-0",
"vue-router": "^4.0.0-0"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^2.33.0", "@typescript-eslint/eslint-plugin": "^2.33.0",
"@typescript-eslint/parser": "^2.33.0", "@typescript-eslint/parser": "^2.33.0",
"@vue/cli-plugin-babel": "~4.5.0", "@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0", "@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "^4.5.4",
"@vue/cli-plugin-typescript": "^4.5.4", "@vue/cli-plugin-typescript": "^4.5.4",
"@vue/cli-service": "~4.5.0", "@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0-0", "@vue/compiler-sfc": "^3.0.0-0",

View File

@ -1,16 +1,22 @@
<template> <template>
<div id="app"> <div id="app">
<Home msg="this message is not displayed"/> <div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<a href="#" @click.stop="authorize">Log On</a>
</div>
<router-view/>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Home from './components/Home.vue' import { authorize } from '@/auth'
export default { export default {
components: { setup() {
Home, return {
}, authorize
}
}
} }
</script> </script>
@ -21,6 +27,18 @@ export default {
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
text-align: center; text-align: center;
color: #2c3e50; color: #2c3e50;
margin-top: 60px; }
#nav {
padding: 30px;
}
#nav a {
font-weight: bold;
color: #2c3e50;
}
#nav a.router-link-exact-active {
color: #42b983;
} }
</style> </style>

View File

@ -0,0 +1,63 @@
/**
* Authentication and Authorization.
*
* This contains authentication and authorization functions needed to permit secure access to the application.
*
* @author Daniel J. Summers <daniel@bitbadger.solutions>
* @version 1
*/
import { CLIENT_SECRET } from './config'
/** Client ID for Jobs, Jobs, Jobs */
const CLIENT_ID = '6Ook3LBff00dOhyBgbf4eXSqIpAroK72aioIdGaDqxs'
/** No Agenda Social's base URL */
const NAS_URL = 'https://noagendasocial.com/'
/** No Agenda Social's base API URL */
const API_URL = `${NAS_URL}api/v1/`
/** The base URL for Jobs, Jobs, Jobs */
const JJJ_URL = `${location.protocol}//${location.host}/`
/**
* Authorize access to this application from No Agenda Social.
*
* This is the first step in a 2-step log on process; this step will prompt the user to authorize Jobs, Jobs, Jobs to
* get information from their No Agenda Social profile. Once that authorization has been granted, we receive an access
* code which we can use to request a full token.
*/
export function authorize() {
const params = new URLSearchParams([
[ 'client_id', CLIENT_ID ],
[ 'scope', 'read' ],
[ 'redirect_uri', `${JJJ_URL}user/authorized` ],
[ 'response_type', 'code' ]
]).toString()
location.assign(`${NAS_URL}oauth/authorize?${params}`)
}
export async function logOn(authCode: string) {
const options: RequestInit = {
method: 'POST',
body: JSON.stringify({
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: `${JJJ_URL}user/authorized`,
grant_type: 'authorization_code',
code: authCode,
scope: 'read'
}),
headers: { 'Content-Type': 'application/json' }
}
const resp = await fetch(`${NAS_URL}oauth/token`, options)
if (resp.ok) {
const token = await resp.json()
// TODO: submit token to server, let server obtain profile from NA Social
console.info(`Success - response ${JSON.stringify(token)}`)
} else {
// TODO: notify the user
const err = await resp.text()
console.error(`Failure - ${err}`)
}
}

View File

@ -1,4 +1,5 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import router from './router'
createApp(App).mount('#app') createApp(App).use(router).mount('#app')

View File

@ -0,0 +1,33 @@
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import Home from '../views/Home.vue'
import Authorized from '../views/user/Authorized.vue'
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: '/user/authorized',
name: 'Authorized',
component: Authorized,
props: (route) => ({ code: route.query.code })
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router

View File

@ -0,0 +1,5 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>

View File

@ -0,0 +1,75 @@
<template>
<div class="hello">
<h1>
Jobs, Jobs, Jobs<br>
<small><small><small><em>
(and Jobs - <a class="audio" @click="playJobs">Let's Vote for Jobs!</a>)
</em></small></small></small>
</h1>
<p>
Future home of No Agenda Jobs, where citizens of Gitmo Nation can assist one another in finding or enhancing
their employment. This will enable them to continue providing value for value to Adam and John, as they continue
their work deconstructing the misinformation that passes for news on a day-to-day basis.
</p>
<p>
Do you not understand the terms in the paragraph above? No worries; just head over to
<a href="https://noagendashow.net">The Best Podcast in the Universe</a> <em><a class="audio" @click="playTrue">(it's true!)</a></em> and find out what
you&rsquo;re missing.
</p>
<audio ref="jobsAudio">
<source src="/pelosi-jobs.mp3">
</audio>
<audio ref="trueAudio">
<source src="/thats-true.mp3">
</audio>
</div>
</template>
<script lang="ts">
import { ref } from 'vue'
export default {
props: {
msg: String
},
setup() {
const jobsAudio = ref(null)
const trueAudio = ref(null)
const playJobs = () => jobsAudio.value.play()
const playTrue = () => trueAudio.value.play()
return {
jobsAudio,
trueAudio,
playJobs,
playTrue
}
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
a.audio {
color: inherit;
border-bottom: dotted 1px lightgray;
}
a.audio:hover {
cursor: pointer;
}
</style>

View File

@ -0,0 +1,18 @@
<template>
<p>Logging you on with No Agenda Social...</p>
</template>
<script lang="ts">
import { logOn } from '@/auth'
export default {
props: {
code: {
type: String
}
},
setup(props) {
logOn(props.code)
}
}
</script>