Fetch microsub endpoint from user (and use it)

This commit is contained in:
Peter Stuifzand 2018-08-29 20:29:54 +02:00
parent 142b6ef28b
commit dcd79702db
4 changed files with 139 additions and 22 deletions

View File

@ -8,6 +8,7 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"isomorphic-fetch": "^2.2.1",
"micropub-helper": "^1.4.0",
"node-sass": "^4.9.3",
"vue": "^2.5.17",

View File

@ -26,6 +26,7 @@
<script>
import Micropub from 'micropub-helper';
import helper from '@/helpers';
import relScraper from '@/helpers/rel-scraper'
const CLIENT_ID = 'https://p83.nl/'
@ -61,14 +62,14 @@
state: state,
scope: 'create post channels timeline'
})
micropub.getAuthUrl().then(url => {
let options = {
micropubEndpoint: micropub.options.micropubEndpoint,
tokenEndpoint: micropub.options.tokenEndpoint,
loginState: state
}
this.$store.dispatch('saveEndpoints', options)
window.location = url
this.$store.dispatch('saveEndpoints', options).then(() => {
window.location = url
})
// eslint-disable-next-line
}).catch(err => console.log(err))
}
@ -92,22 +93,36 @@
me: this.$route.query['me'],
state: this.$store.state.loginState,
scope: 'create post channels timeline',
tokenEndpoint: this.$store.state.tokenEndpoint
})
micropub
.getToken(code)
.then(token => {
this.$store.dispatch('tokenResponse', {
access_token: token,
me: micropub.options.me,
scope: micropub.options.scope
relScraper(this.$route.query['me']).then(rels => {
micropub.options.tokenEndpoint = rels.token_endpoint
micropub.options.authEndpoint = rels.auth_endpoint
micropub.options.micropubEndpoint = rels.micropub
let options = {
tokenEndpoint: rels.token_endpoint,
authEndpoint: rels.auth_endpoint,
micropubEndpoint: rels.micropub,
microsubEndpoint: rels.microsub
}
this.$store.dispatch('saveEndpoints', options)
micropub
.getToken(code)
.then(token => {
this.$store.dispatch('tokenResponse', {
access_token: token,
me: micropub.options.me,
scope: micropub.options.scope
})
this.show = false
this.$router.push('/')
})
this.show = false
this.$router.push('/')
})
// eslint-disable-next-line
.catch(err => console.log(err));
// eslint-disable-next-line
.catch(err => console.log(err));
})
}
}
</script>

103
src/helpers/rel-scraper.js Normal file
View File

@ -0,0 +1,103 @@
import fetch from 'isomorphic-fetch'
export default function(url) {
let baseUrl = url;
let endpoints = {
micropub: null,
microsub: null,
authorization_endpoint: null,
token_endpoint: null,
media_endpoint: null,
};
return new Promise((resolve, reject) => {
fetch(url)
.then(res => {
if (!res.ok) {
return reject('Error getting page');
}
baseUrl = res.url;
// Check for endpoints in headers
const linkHeaders = res.headers.get('link');
if (linkHeaders) {
const links = linkHeaders.split(',');
links.forEach(link => {
Object.keys(endpoints).forEach(key => {
const rel = link.match(/rel=("([^"]*)"|([^,"<]+))/);
if (
rel &&
rel[1] &&
(' ' + rel[1].toLowerCase() + ' ').indexOf(' ' + key + ' ') >= 0
) {
const linkValues = link.match(/[^<>|\s]+/g);
if (linkValues && linkValues[0]) {
let endpointUrl = linkValues[0];
endpointUrl = new URL(endpointUrl, url).toString();
endpoints[key] = endpointUrl;
}
}
});
});
}
return res.text();
})
.then(html => {
// Get rel links
const rels = htmlScraper(html, baseUrl);
// Save necessary endpoints.
if (rels) {
Object.keys(endpoints).forEach(key => {
if (rels[key] && rels[key][0]) {
endpoints[key] = rels[key][0];
}
});
}
return resolve(endpoints);
})
.catch(err => {
// eslint-disable-next-line
console.log(err);
reject('Error fetching url');
});
});
}
function htmlScraper(htmlString, url) {
let rels = {};
let baseUrl = url;
const doc = new DOMParser().parseFromString(htmlString, 'text/html');
const baseEl = doc.querySelector('base[href]');
const relEls = doc.querySelectorAll('[rel][href]');
if (baseEl) {
const value = baseEl.getAttribute('href');
const url = new URL(value, url);
baseUrl = url.toString();
}
if (relEls.length) {
relEls.forEach(relEl => {
const names = relEl
.getAttribute('rel')
.toLowerCase()
.split('\\s+');
const value = relEl.getAttribute('href');
if (names.length && value !== null) {
names.forEach(name => {
if (!rels[name]) {
rels[name] = [];
}
const url = new URL(value, baseUrl).toString();
if (rels[name].indexOf(url) === -1) {
rels[name].push(url)
}
})
}
})
}
return rels
}

View File

@ -2,8 +2,6 @@ import Vue from 'vue'
import Vuex from 'vuex'
import Micropub from 'micropub-helper';
const baseurl = "https://microsub.stuifzandapp.com/microsub"
Vue.use(Vuex)
export default new Vuex.Store({
@ -54,7 +52,7 @@ export default new Vuex.Store({
actions: {
fetchChannels({commit}) {
fetch(baseurl + '?action=channels', {
fetch(this.state.microsubEndpoint + '?action=channels', {
headers: {
'Authorization': 'Bearer ' + this.state.access_token
}
@ -68,7 +66,7 @@ export default new Vuex.Store({
commit('clearTimeline', {channel: channel})
},
fetchTimeline({commit}, channel) {
let url = baseurl + '?action=timeline&channel=' + channel.uid
let url = this.state.microsubEndpoint + '?action=timeline&channel=' + channel.uid
if (channel.after) {
url += '&after=' + channel.after;
}
@ -99,7 +97,7 @@ export default new Vuex.Store({
commit('newAccessToken', response)
},
markRead(x, {channel, entry}) {
let url = baseurl + '?action=timeline&method=mark_read&channel=' + encodeURIComponent(channel) + '&entry=' + encodeURIComponent(entry);
let url = this.state.microsubEndpoint + '?action=timeline&method=mark_read&channel=' + encodeURIComponent(channel) + '&entry=' + encodeURIComponent(entry);
return fetch(url, {
method: 'POST',
headers: {