javascript client somewhat a skeleton.

sse-post-key-prefixes
fiatjaf 2020-11-08 23:31:09 -03:00
rodzic 5924154724
commit 4d51568354
11 zmienionych plików z 343 dodań i 0 usunięć

2
web-client/.gitignore vendored 100644
Wyświetl plik

@ -0,0 +1,2 @@
node_modules
bundle.*

Wyświetl plik

@ -0,0 +1,23 @@
{
"dependencies": {
"boxcrate": "^2.1.1",
"buffer": "^6.0.1",
"elliptic": "^6.5.3",
"sha.js": "^2.4.11",
"vue": "^3.0.2",
"vue-router": "^4.0.0-rc.2",
"vuex": "^4.0.0-rc.1"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^16.0.0",
"@rollup/plugin-inject": "^4.0.2",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^10.0.0",
"@vue/compiler-sfc": "^3.0.2",
"rollup": "^2.33.1",
"rollup-plugin-css-only": "^2.1.0",
"rollup-plugin-inject-process-env": "^1.3.1",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-vue": "^6.0.0-beta.11"
}
}

Wyświetl plik

@ -0,0 +1,50 @@
import vuePlugin from 'rollup-plugin-vue'
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import {terser} from 'rollup-plugin-terser'
import css from 'rollup-plugin-css-only'
import inject from '@rollup/plugin-inject'
import injectProcessEnv from 'rollup-plugin-inject-process-env'
import json from '@rollup/plugin-json'
const production = !!process.env.PRODUCTION
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'static/bundle.js'
},
plugins: [
css({output: 'static/bundle.css'}),
vuePlugin({
include: /\.html$/,
preprocessStyles: true
}),
json({
// exclude: '**/bip39/src/wordlists/!(english).json',
indent: ''
}),
resolve({
browser: true,
preferBuiltins: false
}),
commonjs(),
inject({
Buffer: ['buffer', 'Buffer']
}),
injectProcessEnv({
NODE_ENV: production ? 'production' : 'development'
}),
production && terser()
]
}

Wyświetl plik

@ -0,0 +1,33 @@
<template>
<div class="nav">
<router-link to="/setup">Setup</router-link>
<span class="pubkey">{{ $store.getters.pubKeyHex }}</span>
<router-link to="/">Home</router-link>
</div>
<div>
<router-view />
</div>
</template>
<script>
export default {}
</script>
<style>
.nav {
display: flex;
align-items: center;
}
.nav > * {
margin: 0 10px;
}
.pubkey {
display: inline-block;
width: 160px;
text-overflow: ellipsis;
overflow: hidden;
}
.pubkey:hover {
width: auto;
}
</style>

Wyświetl plik

@ -0,0 +1,61 @@
<template>
<form @submit="publishNote">
<legend>Publishing to {{ writeServersList }}</legend>
<label
>Write anything:
<textarea :disabled="publishing" v-model="text"></textarea>
</label>
<button :disabled="publishing">Publish</button>
</form>
<p>Data providers: {{ readServersList }}</p>
<div v-if="$store.state.loadingNotes">
<p>Loading notes...</p>
</div>
<div v-else-if="$store.state.following.length === 0">
<p>You're not following anyone.</p>
</div>
<div v-else-if="$store.state.notes.length === 0">
<p>Didn't find any data.</p>
</div>
<div v-else>
<div v-for="note in $store.state.notes">
<Note v-bind="note" :key="note.id" />
</div>
</div>
</template>
<script>
export default {
data() {
return {text: '', publishing: false}
},
computed: {
readServersList() {
return JSON.stringify(this.$store.getters.readServers)
.replace(/"/g, '')
.replace(/,/g, ' ')
},
writeServersList() {
return JSON.stringify(this.$store.getters.writeServers)
.replace(/"/g, '')
.replace(/,/g, ' ')
}
},
methods: {
async publishNote(ev) {
ev.preventDefault()
this.publishing = true
try {
await this.$store.dispatch('publishNote', this.text)
this.text = ''
} catch (err) {
console.log('error publishing', err)
}
this.publishing = false
}
}
}
</script>
<style></style>

Wyświetl plik

@ -0,0 +1,5 @@
<template></template>
<script></script>
<style></style>

Wyświetl plik

@ -0,0 +1,5 @@
<template></template>
<script></script>
<style></style>

Wyświetl plik

@ -0,0 +1,21 @@
<template>
<div><b>Secret Key:</b> {{ $store.getters.privkeyHex }}</div>
<div>
<b>Relays:</b>
{{ JSON.stringify($store.state.relays) }}
</div>
<div>
<b>Following:</b>
{{ JSON.stringify($store.state.following) }}
</div>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
<style></style>

Wyświetl plik

@ -0,0 +1,31 @@
import {createApp} from 'vue/dist/vue.esm-bundler.js'
import {createRouter, createWebHashHistory} from 'vue-router'
import App from './App.html'
import Home from './Home.html'
import Setup from './Setup.html'
import Profile from './Profile.html'
import Note from './Note.html'
import store from './store'
const router = createRouter({
history: createWebHashHistory(),
routes: [
{path: '/', component: Home},
{path: '/setup', component: Setup},
{path: '/:key', component: Profile},
{path: '/n/:id', component: Note}
]
})
const app = createApp({})
app.use(router)
app.use(store)
app.component('App', App)
app.component('Home', Home)
app.component('Setup', Setup)
app.component('Profile', Profile)
app.component('Note', Note)
app.mount('#app')

Wyświetl plik

@ -0,0 +1,97 @@
import {createStore, createLogger} from 'vuex'
import BoxCrate from 'boxcrate'
import elliptic from 'elliptic'
import shajs from 'sha.js'
const boxcrate = new BoxCrate({
expiredCheckType: 'active',
expiredCheckInterval: 60000
})
const ec = new elliptic.ec('secp256k1')
export default createStore({
plugins: process.env.NODE_ENV !== 'production' ? [createLogger()] : [],
state() {
var relays = {
'http://0.0.0.0:7447': 'rw'
}
var key = null
let following = []
relays = boxcrate.storage.getItem('relays') || relays
key = boxcrate.storage.getItem('key') || key
following = boxcrate.storage.getItem('following') || following
// generate key if doesn't exist
if (key) key = ec.keyFromPrivate(key, 'hex')
else {
key = ec.genKeyPair()
boxcrate.storage.setItem('key', key.getPrivate('hex'))
}
return {
relays,
key,
following
}
},
getters: {
privKeyHex: state => state.key.getPrivate('hex'),
pubKeyHex: state => state.key.getPublic(true, 'hex'),
writeServers: state =>
Object.keys(state.relays).filter(
host => state.relays[host].indexOf('w') !== -1
),
readServers: state =>
Object.keys(state.relays).filter(
host => state.relays[host].indexOf('r') !== -1
)
},
mutations: {},
actions: {
publishNote(store, text) {
let evt = {
pubkey: store.getters.pubKeyHex,
time: Math.round(new Date().getTime() / 1000),
kind: 1,
content: text
}
let hash = shajs('sha256').update(serializeEvent(evt)).digest()
evt.id = hash.toString('hex')
evt.signature = store.state.key.sign(hash).toDER('hex')
for (let i = 0; i < store.getters.writeServers.length; i++) {
let host = store.getters.writeServers[i]
window.fetch(host + '/save_update', {
method: 'POST',
headers: {'content-type': 'application/json'},
body: JSON.stringify(evt)
})
}
}
}
})
function serializeEvent(evt) {
let version = Buffer.alloc(1)
version.writeUInt8(0)
let pubkey = Buffer.from(evt.pubkey, 'hex')
let time = Buffer.alloc(4)
time.writeUInt32BE(evt.time)
let kind = Buffer.alloc(1)
kind.writeUInt8(kind)
let reference = Buffer.alloc(0)
if (evt.reference) {
reference = Buffer.from(evt.reference, 'hex')
}
let content = Buffer.from(evt.content)
return Buffer.concat([version, pubkey, time, kind, reference, content])
}

Wyświetl plik

@ -0,0 +1,15 @@
<!DOCTYPE html>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>profiles 📡</title>
<link rel="stylesheet" href="/bundle.css" />
<body>
<div id="app">
<App />
</div>
</body>
<script src="/bundle.js"></script>