Get access token from mstdn.jp

This commit is contained in:
AkiraFukushima 2018-03-08 17:41:39 +09:00
parent 3f0acaf83a
commit a3554ec281
12 changed files with 1508 additions and 272 deletions

1566
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -56,21 +56,26 @@
}
},
"dependencies": {
"vue": "^2.3.3",
"axios": "^0.16.1",
"element-ui": "^2.2.1",
"mastodon-api": "^1.3.0",
"vue": "^2.3.3",
"vue-electron": "^1.0.6",
"vue-router": "^2.5.3",
"vuex": "^2.3.1"
},
"devDependencies": {
"babel-core": "^6.25.0",
"babel-eslint": "^7.2.3",
"babel-loader": "^7.1.1",
"babel-plugin-istanbul": "^4.1.1",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.0",
"babel-preset-stage-0": "^6.24.1",
"babel-register": "^6.24.1",
"babili-webpack-plugin": "^0.1.2",
"cfonts": "^1.1.3",
"chai": "^4.0.0",
"chalk": "^2.1.0",
"copy-webpack-plugin": "^4.0.1",
"cross-env": "^5.0.5",
@ -78,15 +83,14 @@
"del": "^3.0.0",
"devtron": "^1.4.0",
"electron": "^1.7.5",
"electron-builder": "^19.19.1",
"electron-debug": "^1.4.0",
"electron-devtools-installer": "^2.2.0",
"electron-builder": "^19.19.1",
"babel-eslint": "^7.2.3",
"eslint": "^4.4.1",
"eslint-config-standard": "^10.2.1",
"eslint-friendly-formatter": "^3.0.0",
"eslint-loader": "^1.9.0",
"eslint-plugin-html": "^3.1.1",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-node": "^5.1.1",
"eslint-plugin-promise": "^3.5.0",
@ -103,14 +107,13 @@
"karma-sourcemap-loader": "^0.3.7",
"karma-spec-reporter": "^0.0.31",
"karma-webpack": "^2.0.1",
"webpack-merge": "^4.1.0",
"require-dir": "^0.3.0",
"spectron": "^3.7.1",
"babel-plugin-istanbul": "^4.1.1",
"chai": "^4.0.0",
"mocha": "^3.0.2",
"multispinner": "^0.2.1",
"node-loader": "^0.6.0",
"node-sass": "^4.7.2",
"require-dir": "^0.3.0",
"sass-loader": "^6.0.7",
"spectron": "^3.7.1",
"style-loader": "^0.18.2",
"url-loader": "^0.5.9",
"vue-html-loader": "^1.2.4",
@ -119,6 +122,7 @@
"vue-template-compiler": "^2.4.2",
"webpack": "^3.5.2",
"webpack-dev-server": "^2.7.1",
"webpack-hot-middleware": "^2.18.2"
"webpack-hot-middleware": "^2.18.2",
"webpack-merge": "^4.1.0"
}
}

35
src/main/auth.js Normal file
View File

@ -0,0 +1,35 @@
import Mastodon from 'mastodon-api'
const appName = 'whalebird'
const scope = 'read write follow'
const redirectURI = 'urn:ietf:wg:oauth:2.0:oob'
export default class Authentication {
constructor (baseURL = 'https://mstdn.jp') {
this.baseURL = baseURL
this.clientId = ''
this.clientSecret = ''
}
getAuthorizationUrl () {
return Mastodon.createOAuthApp(this.baseURL + '/api/v1/apps', appName, scope, redirectURI)
.catch(err => console.error(err))
.then((res) => {
console.log('Please save \'id\', \'client_id\' and \'client_secret\' in your program and use it from now on!')
console.log(res)
this.clientId = res.client_id
this.clientSecret = res.client_secret
return Mastodon.getAuthorizationUrl(this.clientId, this.clientSecret, this.baseURL, scope, redirectURI)
})
}
getAccessToken (code) {
console.log(code)
console.log(this.clientId)
console.log(this.clientSecret)
console.log(this.baseURL)
return Mastodon.getAccessToken(this.clientId, this.clientSecret, code, this.baseURL)
}
}

View File

@ -1,6 +1,7 @@
'use strict'
import { app, BrowserWindow } from 'electron'
import { app, ipcMain, BrowserWindow, shell } from 'electron'
import Authentication from './auth'
/**
* Set `__static` path to static files in production
@ -46,6 +47,26 @@ app.on('activate', () => {
}
})
let auth = new Authentication()
// TODO: error handling
ipcMain.on('get-auth-link', (event, _) => {
auth.getAuthorizationUrl()
.catch(err => console.error(err))
.then((url) => {
console.log(url)
event.sender.send('auth-link-reply', url)
shell.openExternal(url)
})
})
// TODO: error handling
ipcMain.on('get-access-token', (event, code) => {
auth.getAccessToken(code)
.catch(err => console.error(err))
.then(token => console.log(token))
})
/**
* Auto Updater
*

View File

@ -0,0 +1,36 @@
<template>
<div id="authorize">
<el-form ref="form" :model="authorizeForm" label-width="120px" label-position="top">
<el-form-item label="Please paste authorization code from your browser:">
<el-input v-model="authorizeForm.code"></el-input>
</el-form-item>
<el-form-item class="submit">
<el-button type="primary" @click="authorizeSubmit">Submit</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: 'authorize',
data () {
return {
authorizeForm: {
code: ''
}
}
},
methods: {
authorizeSubmit () {
this.$store.dispatch('Authorize/submit', this.authorizeForm.code)
}
}
}
</script>
<style lang="scss" scoped>
#authorize {
text-align: center;
}
</style>

View File

@ -1,4 +1,4 @@
<template>
3<template>
<div id="wrapper">
<img id="logo" src="~@/assets/logo.png" alt="electron-vue">
<main>
@ -8,7 +8,7 @@
</span>
<system-information></system-information>
</div>
<router-link to="/login">login</router-link>
<div class="right-side">
<div class="doc">
<div class="title">Getting Started</div>

View File

@ -0,0 +1,25 @@
<template>
<div id="login">
<el-button type="primary" @click="login">Login</el-button>
</div>
</template>
<script>
export default {
name: 'login',
methods: {
login () {
this.$store.dispatch('Login/fetchLogin')
.then((url) => {
this.$router.push({ path: '/authorize' })
})
}
}
}
</script>
<style lang="scss" scoped>
#login {
text-align: center;
}
</style>

View File

@ -1,10 +1,14 @@
import Vue from 'vue'
import axios from 'axios'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import App from './App'
import router from './router'
import store from './store'
Vue.use(ElementUI)
if (!process.env.IS_WEB) Vue.use(require('vue-electron'))
Vue.http = Vue.prototype.$http = axios
Vue.config.productionTip = false

View File

@ -10,6 +10,16 @@ export default new Router({
name: 'landing-page',
component: require('@/components/LandingPage').default
},
{
path: '/login',
name: 'login',
component: require('@/components/Login').default
},
{
path: '/authorize',
name: 'authorize',
component: require('@/components/Authorize').default
},
{
path: '*',
redirect: '/'

View File

@ -0,0 +1,20 @@
import { ipcRenderer } from 'electron'
const Authorize = {
namespaced: true,
state: {},
mutations: {},
actions: {
submit ({ commit }, code) {
return new Promise((resolve, reject) => {
ipcRenderer.send('get-access-token', code)
ipcRenderer.on('access-token-reply', (event, arg) => {
console.log(arg)
resolve(arg)
})
})
}
}
}
export default Authorize

View File

@ -0,0 +1,19 @@
import { ipcRenderer } from 'electron'
const Login = {
namespaced: true,
state: {},
mutations: {},
actions: {
fetchLogin ({ commit }) {
return new Promise((resolve, reject) => {
ipcRenderer.send('get-auth-link', 'get')
ipcRenderer.on('auth-link-reply', (event, arg) => {
resolve(arg)
})
})
}
}
}
export default Login

View File

@ -1,11 +1,19 @@
import Vue from 'vue'
import Vuex from 'vuex'
import createLogger from 'vuex/dist/logger'
import modules from './modules'
import Login from './Login'
import Authorize from './Authorize'
Vue.use(Vuex)
export default new Vuex.Store({
modules,
strict: process.env.NODE_ENV !== 'production'
strict: process.env.NODE_ENV !== 'production',
plugins: process.env.NODE_ENV !== 'production'
? [createLogger()]
: [],
modules: {
Login,
Authorize
}
})