Cleanup webpush code

This commit is contained in:
Pavel Djundik 2019-11-12 22:03:59 +02:00
parent 17365d9967
commit 7584f47c7d
9 changed files with 75 additions and 135 deletions

View file

@ -16,17 +16,6 @@
<NetworkList />
</div>
<footer id="footer">
<span class="tooltipped tooltipped-n tooltipped-no-touch" aria-label="Sign in"
><router-link
to="/sign-in"
tag="button"
active-class="active"
:class="['icon', 'sign-in']"
aria-label="Sign in"
role="tab"
aria-controls="sign-in"
:aria-selected="$route.name === 'SignIn'"
/></span>
<span
class="tooltipped tooltipped-n tooltipped-no-touch"
aria-label="Connect to network"

View file

@ -450,6 +450,7 @@
<script>
import socket from "../../js/socket";
import webpush from "../../js/webpush";
import RevealPassword from "../RevealPassword.vue";
import Session from "../Session.vue";
import SidebarToggle from "../SidebarToggle.vue";
@ -481,10 +482,6 @@ export default {
if (window.navigator.registerProtocolHandler) {
this.canRegisterProtocol = true;
}
// TODO: Rework push notification code to avoid reinitializing it here
const webpush = require("../../js/webpush");
webpush.initialize();
},
methods: {
onChange(event) {
@ -551,8 +548,7 @@ export default {
pop.play();
},
onPushButtonClick() {
const webpush = require("../../js/webpush"); // TODO: do this in a smarter way
webpush.onPushButton();
webpush.togglePushSubscription();
},
},
};

View file

@ -324,7 +324,6 @@ kbd {
#sidebar .chan.special::before { content: "\f03a"; /* http://fontawesome.io/icon/list/ */ }
#footer .sign-in::before { content: "\f023"; /* http://fontawesome.io/icon/lock/ */ }
#footer .connect::before { content: "\f067"; /* http://fontawesome.io/icon/plus/ */ }
#footer .settings::before { content: "\f013"; /* http://fontawesome.io/icon/cog/ */ }
#footer .help::before { content: "\f059"; /* http://fontawesome.io/icon/question/ */ }
@ -854,26 +853,6 @@ background on hover (unless active) */
border-radius: 5px;
}
.signed-out #footer .sign-in {
display: inline-block;
}
.signed-out #footer .connect {
display: none;
}
.public #footer .sign-in {
display: none;
}
#footer .sign-in {
display: none;
}
.signed-out #sidebar {
display: none; /* Hide the sidebar when user is signed out */
}
#windows li,
#windows p,
#windows label,

View file

@ -47,7 +47,7 @@
<meta name="theme-color" content="<%- themeColor %>">
</head>
<body class="signed-out<%- public ? " public" : "" %>" data-transports="<%- JSON.stringify(transports) %>">
<body class="<%- public ? " public" : "" %>" data-transports="<%- JSON.stringify(transports) %>">
<div id="loading">
<div class="window">
<div id="loading-status-container">

View file

@ -2,7 +2,6 @@
const $ = require("jquery");
const socket = require("../socket");
const webpush = require("../webpush");
const upload = require("../upload");
const store = require("../store").default;
const router = require("../router");
@ -33,7 +32,6 @@ socket.once("configuration", function(data) {
upload.initialize();
}
webpush.initialize();
router.initialize();
// If localStorage contains a theme that does not exist on this server, switch

View file

@ -1,7 +1,6 @@
"use strict";
const socket = require("../socket");
const webpush = require("../webpush");
const storage = require("../localStorage");
const {router, switchToChannel, navigate} = require("../router");
const store = require("../store").default;
@ -18,11 +17,6 @@ socket.on("init", function(data) {
if (!store.state.appLoaded) {
store.commit("appLoaded");
// TODO: Try to move webpush key to configuration event
webpush.configurePushNotifications(data.pushSubscription, data.applicationServerKey);
document.body.classList.remove("signed-out");
if (window.g_TheLoungeRemoveLoading) {
window.g_TheLoungeRemoveLoading();
}

View file

@ -1,13 +1,9 @@
"use strict";
const storage = require("./localStorage");
const socket = require("./socket");
const store = require("./store").default;
const {switchToChannel} = require("./router");
let clientSubscribed = null;
let applicationServerKey;
if ("serviceWorker" in navigator) {
navigator.serviceWorker.addEventListener("message", (event) => {
if (event.data && event.data.type === "open") {
@ -23,55 +19,50 @@ if ("serviceWorker" in navigator) {
module.exports.hasServiceWorker = false;
module.exports.configurePushNotifications = (subscribedOnServer, key) => {
applicationServerKey = key;
// If client has push registration but the server knows nothing about it,
// this subscription is broken and client has to register again
if (clientSubscribed === true && subscribedOnServer === false) {
store.commit("pushNotificationState", "loading");
navigator.serviceWorker.ready
.then((registration) => registration.pushManager.getSubscription())
.then((subscription) => subscription && subscription.unsubscribe())
.then((successful) => {
store.commit("pushNotificationState", successful ? "supported" : "unsupported");
});
}
};
module.exports.initialize = () => {
socket.once("push:issubscribed", function(hasSubscriptionOnServer) {
if (!isAllowedServiceWorkersHost()) {
store.commit("pushNotificationState", "nohttps");
return;
}
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("service-worker.js")
.then((registration) => {
module.exports.hasServiceWorker = true;
if (!("serviceWorker" in navigator)) {
return;
}
if (!registration.pushManager) {
return;
}
navigator.serviceWorker
.register("service-worker.js")
.then((registration) => {
module.exports.hasServiceWorker = true;
return registration.pushManager.getSubscription().then((subscription) => {
clientSubscribed = !!subscription;
if (!registration.pushManager) {
return;
}
return registration.pushManager.getSubscription().then((subscription) => {
// If client has push registration but the server knows nothing about it,
// this subscription is broken and client has to register again
if (subscription && hasSubscriptionOnServer === false) {
subscription.unsubscribe().then((successful) => {
store.commit(
"pushNotificationState",
successful ? "supported" : "unsupported"
);
});
} else {
store.commit(
"pushNotificationState",
clientSubscribed ? "subscribed" : "supported"
subscription ? "subscribed" : "supported"
);
});
})
.catch(() => {
store.commit("pushNotificationState", "unsupported");
}
});
}
};
})
.catch((err) => {
store.commit("pushNotificationState", "unsupported");
console.error(err); // eslint-disable-line no-console
});
});
module.exports.onPushButton = () => {
module.exports.togglePushSubscription = () => {
store.commit("pushNotificationState", "loading");
navigator.serviceWorker.ready
@ -80,62 +71,31 @@ module.exports.onPushButton = () => {
if (existingSubscription) {
socket.emit("push:unregister");
return existingSubscription.unsubscribe().then(() => {
store.commit("pushNotificationState", "supported");
return existingSubscription.unsubscribe().then((successful) => {
store.commit(
"pushNotificationState",
successful ? "supported" : "unsupported"
);
});
}
return registration.pushManager
.subscribe({
applicationServerKey: urlBase64ToUint8Array(applicationServerKey),
applicationServerKey: store.state.serverConfiguration.applicationServerKey,
userVisibleOnly: true,
})
.then((subscription) => {
const rawKey = subscription.getKey ? subscription.getKey("p256dh") : "";
const key = rawKey
? window.btoa(String.fromCharCode(...new Uint8Array(rawKey)))
: "";
const rawAuthSecret = subscription.getKey
? subscription.getKey("auth")
: "";
const authSecret = rawAuthSecret
? window.btoa(String.fromCharCode(...new Uint8Array(rawAuthSecret)))
: "";
socket.emit("push:register", {
token: storage.get("token"),
endpoint: subscription.endpoint,
keys: {
p256dh: key,
auth: authSecret,
},
});
socket.emit("push:register", subscription.toJSON());
store.commit("pushNotificationState", "subscribed");
});
})
)
.catch(() => {
.catch((err) => {
store.commit("pushNotificationState", "unsupported");
console.error(err); // eslint-disable-line no-console
});
return false;
};
function urlBase64ToUint8Array(base64String) {
const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
function isAllowedServiceWorkersHost() {
return (
location.protocol === "https:" ||

View file

@ -645,8 +645,6 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
const sendInitEvent = (tokenToSend) => {
socket.emit("init", {
applicationServerKey: manager.webPush.vapidKeys.publicKey,
pushSubscription: client.config.sessions[token],
active: openChannel,
networks: client.networks.map((network) =>
network.getFilteredClone(openChannel, lastMessage)
@ -695,6 +693,7 @@ function getClientConfiguration() {
]);
}
config.applicationServerKey = manager.webPush.vapidKeys.publicKey;
config.version = pkg.version;
config.gitCommit = Helper.getGitCommit();
config.themes = themes.getAll();
@ -740,6 +739,11 @@ function performAuthentication(data) {
// and the client listens to this event only once
if (!data.hasConfig) {
socket.emit("configuration", getClientConfiguration());
socket.emit(
"push:issubscribed",
token && client.config.sessions[token].pushSubscription ? true : false
);
}
client.config.browser = {

View file

@ -101,18 +101,38 @@ describe("Server", function() {
});
});
it("should emit configuration message", (done) => {
client.on("configuration", (data) => {
// Private key defined in vapid.json is "01020304050607080910111213141516" for this public key.
expect(data.applicationServerKey).to.equal(
"BM0eTDpvDnH7ewlHuXWcPTE1NjlJ06XWIS1cQeBTZmsg4EDx5sOpY7kdX1pniTo8RakL3UdfFuIbC8_zog_BWIM"
);
expect(data.public).to.equal(true);
expect(data.defaultTheme).to.equal("default");
expect(data.themes).to.be.an("array");
expect(data.lockNetwork).to.equal(false);
expect(data.displayNetwork).to.equal(true);
expect(data.useHexIp).to.equal(false);
done();
});
});
it("should emit push subscription state message", (done) => {
client.on("push:issubscribed", (data) => {
expect(data).to.be.false;
done();
});
});
it("should emit init message", (done) => {
client.on("init", (data) => {
expect(data.active).to.equal(-1);
expect(data.networks).to.be.an("array");
expect(data.networks).to.be.empty;
expect(data.token).to.be.null;
expect(data.pushSubscription).to.be.undefined;
// Private key defined in vapid.json is "01020304050607080910111213141516" for this public key.
expect(data.applicationServerKey).to.equal(
"BM0eTDpvDnH7ewlHuXWcPTE1NjlJ06XWIS1cQeBTZmsg4EDx5sOpY7kdX1pniTo8RakL3UdfFuIbC8_zog_BWIM"
);
done();
});