parent
36d70399a9
commit
6ae9b9fc56
@ -1,2 +1,55 @@
|
||||
# simple-frontend-xmpp-riotjs
|
||||
# xmpp-login-riotjs
|
||||
|
||||
Small Prototyp to show login to an XMPP-Server with (xmpp.js)[https://github.com/xmppjs/xmpp.js] and retrieve Contacts from Account. Frontend is written in Riotjs, this
|
||||
only tested for an Connection with Websocket (wss://<domain>/xmpp-websocket). The Configuration is below.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Prosody
|
||||
|
||||
```
|
||||
modules_enabled = {
|
||||
"websocket";
|
||||
}
|
||||
|
||||
cross_domain_websocket = { "127.0.0.1:8080", "<domain>" }
|
||||
consider_websocket_secure = true
|
||||
```
|
||||
|
||||
### Nginx
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name <domain>;
|
||||
return 301 https://<domain>$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/<domain>/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/<domain>/privkey.pem;
|
||||
|
||||
server_name <domain>;
|
||||
|
||||
# logs
|
||||
access_log /var/log/nginx/<domain>.access.log;
|
||||
error_log /var/log/nginx/<domain>.error.log;
|
||||
|
||||
location /xmpp-websocket {
|
||||
proxy_pass http://127.0.0.1:5280;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 900s;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"/public/js/spritemap.js": "/public/js/spritemap.js?id=5f6ef07e17161cb70e40e792ba88e1fa",
|
||||
"/public/js/script.js": "/public/js/script.js?id=934c0625608089c8b72e0a7de4e073ed",
|
||||
"/public/css/styles.css": "/public/css/styles.css?id=2ccc88f544c350d3ce83a02c6d9e0a54",
|
||||
"/public/css/IBMPlexMono-Bold.eot": "/public/css/IBMPlexMono-Bold.eot?id=ef1fadf711db80a00542b202ab14f7ee",
|
||||
"/public/css/IBMPlexMono-Bold.ttf": "/public/css/IBMPlexMono-Bold.ttf?id=e46cace25a93f48a2ec32800717827cb",
|
||||
"/public/css/IBMPlexMono-Bold.woff": "/public/css/IBMPlexMono-Bold.woff?id=8864bd7cb954c4646045e3fc0bdec90c",
|
||||
"/public/css/IBMPlexMono-Bold.woff2": "/public/css/IBMPlexMono-Bold.woff2?id=c6d3f08fe7a9fecab40d748b98c87cc5",
|
||||
"/public/css/IBMPlexMono.eot": "/public/css/IBMPlexMono.eot?id=d68f064d6b86ff47b38ad486a3362d82",
|
||||
"/public/css/IBMPlexMono.ttf": "/public/css/IBMPlexMono.ttf?id=60d8ae961dba3289c1d2d54e0b85c9b7",
|
||||
"/public/css/IBMPlexMono.woff": "/public/css/IBMPlexMono.woff?id=18a7a5a76b4176759e2e1b3e674a7f82",
|
||||
"/public/css/IBMPlexMono.woff2": "/public/css/IBMPlexMono.woff2?id=428bd06c5eb0362494016994c26188b4"
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,19 @@
|
||||
{
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@riotjs/observable": "^4.1.1",
|
||||
"@tiny-components/plain-ui": "^0.6.0",
|
||||
"@tiny-components/validator": "^0.2.0",
|
||||
"@xmpp-plugins/roster": "^1.2.0",
|
||||
"@xmpp/client": "^0.13.1",
|
||||
"riot": "^6.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@riotjs/webpack-loader": "^6.0.0",
|
||||
"laravel-mix": "^6.0.43",
|
||||
"laravel-mix-purgecss": "^6.0.0",
|
||||
"sass": "^1.51.0",
|
||||
"sass-loader": "^12.6.0",
|
||||
"svg-spritemap-webpack-plugin": "^4.4.0"
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Lessons Learned | Xmpp</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
<link href="/css/styles.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="header">
|
||||
<div class="bar">
|
||||
<div class="bar__start">
|
||||
<h1 class="m-top-4 m-bottom-4 h4">
|
||||
Xmpp
|
||||
</h1>
|
||||
</div>
|
||||
<div class="bar__main justify-end">
|
||||
<a class="button button--small m-left-sm-3 m-bottom-0" href="https://gitea.node001.net/tiny-components/validator" rel="noopener" target="_blank">
|
||||
Gitea
|
||||
<svg class="m-left-3 icon fill-text" aria-hidden="true">
|
||||
<use xlink:href="symbol-defs.svg#icon-gitea"></use>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
<div class="grid justify-center">
|
||||
<div class="col-12 col-md-6">
|
||||
<xmpp-login></xmpp-login>
|
||||
<xmpp-contacts></xmpp-contacts>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="/js/script.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
||||
(self.webpackChunk=self.webpackChunk||[]).push([[355],{1256:()=>{}}]);
|
After Width: | Height: | Size: 66 KiB |
@ -0,0 +1,51 @@
|
||||
<xmpp-contacts>
|
||||
<div class="panel m-top-6" if={ state.contacts.length > 0 }>
|
||||
<div class="bar">
|
||||
<div class="bar__main">
|
||||
Contacts
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel__body">
|
||||
<ul>
|
||||
<li each={ contact in state.contacts }>
|
||||
{ contact.name }
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
import setupRoster from "@xmpp-plugins/roster"
|
||||
import xmppStore from './../stores/xmpp.js'
|
||||
|
||||
export default {
|
||||
state: {
|
||||
contacts: []
|
||||
},
|
||||
|
||||
onMounted() {
|
||||
xmppStore.on('online', (address) => {
|
||||
const roster = setupRoster(xmppStore.xmpp)
|
||||
|
||||
roster.get().then(roster => {
|
||||
if (!roster) {
|
||||
// the roster hasn't changed since last version
|
||||
return
|
||||
}
|
||||
|
||||
const { version, items } = roster
|
||||
|
||||
this.state.contacts = items
|
||||
this.update()
|
||||
})
|
||||
})
|
||||
|
||||
xmppStore.on('offline', (address) => {
|
||||
this.state.contacts = []
|
||||
this.update()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</xmpp-contacts>
|
@ -0,0 +1,142 @@
|
||||
<xmpp-login>
|
||||
<div class="panel m-top-6">
|
||||
<div class="bar">
|
||||
<div class="bar__start">
|
||||
Account
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel__body">
|
||||
<form onsubmit={ (event) => { state.validator.submit(event) }} if={ !state.isOnline }>
|
||||
<div class="field-group">
|
||||
<label class="field-label">
|
||||
Service
|
||||
<input type="text" class="field-text" name="service" />
|
||||
<field-error name="service"></field-error>
|
||||
</label>
|
||||
</div>
|
||||
<div class="field-group">
|
||||
<label class="field-label">
|
||||
Username
|
||||
<input type="text" class="field-text" name="username" />
|
||||
<field-error name="username"></field-error>
|
||||
</label>
|
||||
</div>
|
||||
<div class="field-group">
|
||||
<label class="field-label">
|
||||
Password
|
||||
<input type="password" class="field-text" name="password" />
|
||||
<field-error name="password"></field-error>
|
||||
</label>
|
||||
</div>
|
||||
<div class="loading" if={ state.isLoading }>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
<div class="m-top-4">
|
||||
<button class="button button--full button--success center w-100" disabled={ state.isLoading } type="submit">
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div if={ state.isOnline }>
|
||||
<button class="button button--full button--danger center w-100 m-bottom-0" type="button" onclick={ (event) => { handleLogout(event) } }>
|
||||
Logout
|
||||
</button>
|
||||
</diV>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
import * as riot from 'riot'
|
||||
|
||||
import FormValidator from '@tiny-components/validator/src/formValidator.js'
|
||||
|
||||
import FieldError from '@tiny-components/validator/src/fieldError.riot'
|
||||
riot.register('field-error', FieldError)
|
||||
|
||||
import xmppStore from './../stores/xmpp.js'
|
||||
|
||||
/**
|
||||
* show login form to connect
|
||||
*
|
||||
*/
|
||||
export default {
|
||||
|
||||
state: {
|
||||
isLoading: false,
|
||||
isOnline: false,
|
||||
validator: false
|
||||
},
|
||||
|
||||
onMounted() {
|
||||
|
||||
this.createForm()
|
||||
|
||||
xmppStore.on('error', (error) => {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
xmppStore.on('online', () => {
|
||||
this.isLoading = false
|
||||
|
||||
this.state.isOnline = true
|
||||
this.state.validator = false
|
||||
|
||||
this.update()
|
||||
})
|
||||
|
||||
xmppStore.on('offline', () => {
|
||||
this.isLoading = false
|
||||
this.state.isOnline = false
|
||||
|
||||
this.update()
|
||||
|
||||
this.createForm()
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
createForm() {
|
||||
this.state.validator = new FormValidator(this.$('form'), {
|
||||
'service': {
|
||||
'presence': true
|
||||
},
|
||||
'username': {
|
||||
'presence': true
|
||||
},
|
||||
'password': {
|
||||
'presence': true
|
||||
}
|
||||
}, true)
|
||||
|
||||
this.state.validator.onError((event) => {
|
||||
this.isLoading = false
|
||||
this.update()
|
||||
})
|
||||
|
||||
this.state.validator.onSuccess((event, data) => {
|
||||
event.preventDefault()
|
||||
|
||||
this.isLoading = true
|
||||
this.update()
|
||||
|
||||
xmppStore.login(data.username, data.password, data.service)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
handleLogout()
|
||||
{
|
||||
xmppStore.logout()
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</xmpp-login>
|
@ -0,0 +1,12 @@
|
||||
import * as riot from 'riot'
|
||||
|
||||
import XmppLogin from './components/xmpp-login.riot'
|
||||
import XmppContacts from './components/xmpp-contacts.riot'
|
||||
|
||||
// register components
|
||||
riot.register('xmpp-login', XmppLogin)
|
||||
riot.register('xmpp-contacts', XmppContacts)
|
||||
|
||||
// mount components
|
||||
riot.mount('xmpp-login')
|
||||
riot.mount('xmpp-contacts')
|
@ -0,0 +1,49 @@
|
||||
import { client, xml, jid } from '@xmpp/client'
|
||||
import observable from '@riotjs/observable'
|
||||
|
||||
/**
|
||||
* NotificationService
|
||||
*
|
||||
*
|
||||
*/
|
||||
export default observable({
|
||||
|
||||
login(username, password, service) {
|
||||
|
||||
// don't login twice
|
||||
if (this.xmpp) {
|
||||
return
|
||||
}
|
||||
|
||||
this.xmpp = client({
|
||||
service: service,
|
||||
username: username,
|
||||
password: password
|
||||
})
|
||||
|
||||
this.xmpp.on('error', (error) => {
|
||||
this.xmpp = false
|
||||
this.trigger('error', error)
|
||||
})
|
||||
|
||||
// handle if client goes online
|
||||
this.xmpp.on('online', (address) => {
|
||||
this.trigger('online', address)
|
||||
})
|
||||
|
||||
this.xmpp.on('offline', () => {
|
||||
this.xmpp = false
|
||||
this.trigger('offline')
|
||||
})
|
||||
|
||||
// connect
|
||||
this.xmpp.start()
|
||||
|
||||
},
|
||||
|
||||
logout()
|
||||
{
|
||||
this.xmpp.stop()
|
||||
}
|
||||
})
|
||||
|
@ -0,0 +1,9 @@
|
||||
@import
|
||||
|
||||
'@tiny-components/plain-ui/src/scss/plain-ui';
|
||||
|
||||
|
||||
ul {
|
||||
list-style: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
const mix = require('laravel-mix')
|
||||
const path = require('path')
|
||||
|
||||
require('laravel-mix-purgecss')
|
||||
|
||||
// plugins
|
||||
const SvgSpritemapPlugin = require('svg-spritemap-webpack-plugin')
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Mix Asset Management
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Mix provides a clean, fluent API for defining some Webpack build steps
|
||||
| for your Laravel applications. By default, we are compiling the CSS
|
||||
| file for the application as well as bundling up all the JS files.
|
||||
|
|
||||
*/
|
||||
|
||||
|
||||
mix.webpackConfig({
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.riot$/,
|
||||
use: [{
|
||||
loader: '@riotjs/webpack-loader',
|
||||
options: {
|
||||
hot: false
|
||||
}
|
||||
}]
|
||||
}
|
||||
]},
|
||||
plugins: [
|
||||
new SvgSpritemapPlugin('./node_modules/@tiny-components/plain-ui/src/icons/mono-icons/svg/*.svg', {
|
||||
output: {
|
||||
filename: 'public/symbol-defs.svg',
|
||||
chunk: {
|
||||
keep: true
|
||||
},
|
||||
svgo: {
|
||||
plugins: [{
|
||||
name: 'convertStyleToAttrs',
|
||||
active: true
|
||||
},{
|
||||
name: 'removeStyleElement',
|
||||
active: true
|
||||
}, {
|
||||
name: 'removeAttrs',
|
||||
params: {
|
||||
attrs: 'fill'
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
sprite: {
|
||||
prefix: 'icon-'
|
||||
}
|
||||
})
|
||||
]
|
||||
})
|
||||
|
||||
mix
|
||||
.setPublicPath('./')
|
||||
.js('src/js/script.js', 'public/js')
|
||||
.sass('src/scss/styles.scss', 'public/css')
|
||||
.purgeCss({
|
||||
extend: {
|
||||
content: [
|
||||
path.join(__dirname, 'public/index.html'),
|
||||
path.join(__dirname, 'src/js/**/*.riot')
|
||||
]
|
||||
}
|
||||
})
|
||||
.options({
|
||||
terser: {
|
||||
extractComments: false,
|
||||
},
|
||||
processCssUrls: false
|
||||
})
|
||||
.copyDirectory('node_modules/@tiny-components/plain-ui/src/fonts/IBM*', 'public/css')
|
||||
.version()
|
Loading…
Reference in new issue