Compare commits

..

5 Commits

Author SHA1 Message Date
David Baker
8c09da4294 more s/type/nodeName/ 2020-05-13 19:33:37 +01:00
David Baker
b447b0c62d Use nodeName which is specced 2020-05-13 18:44:06 +01:00
David Baker
cdef07ca2c Log details about the node that failed to be removed / inserted 2020-05-13 18:20:38 +01:00
David Baker
33f22ac483 typo 2020-05-13 17:00:02 +01:00
David Baker
a35d566551 Patch removeNode / insertBefore to fix React crash with Google translate
Hopefully all the info for this is in the comment.

Fixes https://github.com/vector-im/riot-web/issues/13557
2020-05-13 16:44:39 +01:00
35 changed files with 1219 additions and 1449 deletions

View File

@@ -1,152 +1,3 @@
Changes in [1.6.3](https://github.com/vector-im/riot-web/releases/tag/v1.6.3) (2020-06-04)
==========================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v1.6.3-rc.1...v1.6.3)
## Security notice
Riot Web 1.6.3 fixes a vulnerability in single sign-on (SSO) deployments where Riot Web could be confused into sending authentication details to an attacker-controlled server. Thanks to Quentin Gliech for responsibly disclosing this via Matrix's Security Disclosure Policy.
## All changes
* Fix login loop where the sso flow returns to `#/login` to release
[\#13915](https://github.com/vector-im/riot-web/pull/13915)
Changes in [1.6.3-rc.1](https://github.com/vector-im/riot-web/releases/tag/v1.6.3-rc.1) (2020-06-02)
====================================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v1.6.2...v1.6.3-rc.1)
* Upgrade to JS SDK 6.2.0-rc.1 and React SDK 2.7.0-rc.2
* Get rid of welcome.html's Chat with Riot Bot button
[\#13842](https://github.com/vector-im/riot-web/pull/13842)
* Update from Weblate
[\#13886](https://github.com/vector-im/riot-web/pull/13886)
* Allow deferring of Update Toast until the next morning
[\#13864](https://github.com/vector-im/riot-web/pull/13864)
* Give contextual feedback for manual update check instead of banner
[\#13862](https://github.com/vector-im/riot-web/pull/13862)
* Add app-load doc
[\#13834](https://github.com/vector-im/riot-web/pull/13834)
* Update Modular hosting link
[\#13777](https://github.com/vector-im/riot-web/pull/13777)
* Replace New Version Bar with a Toast
[\#13776](https://github.com/vector-im/riot-web/pull/13776)
* Remove webpack-build-notifier from lockfile
[\#13814](https://github.com/vector-im/riot-web/pull/13814)
* Add media queries and mobile viewport (#12142)
[\#13818](https://github.com/vector-im/riot-web/pull/13818)
* Fix @types/react conflict in matrix-react-sdk
[\#13809](https://github.com/vector-im/riot-web/pull/13809)
* Fix manual update checking, super in arrow funcs doesn't work
[\#13808](https://github.com/vector-im/riot-web/pull/13808)
* Update from Weblate
[\#13806](https://github.com/vector-im/riot-web/pull/13806)
* Convert platforms to Typescript
[\#13756](https://github.com/vector-im/riot-web/pull/13756)
* Fix EventEmitter typescript signature in node typings
[\#13764](https://github.com/vector-im/riot-web/pull/13764)
* Add docs and labs flag for new room list implementation
[\#13675](https://github.com/vector-im/riot-web/pull/13675)
* Add font scaling labs setting.
[\#13352](https://github.com/vector-im/riot-web/pull/13352)
* Add labs flag for alternate message layouts
[\#13350](https://github.com/vector-im/riot-web/pull/13350)
* Move dispatcher references in support of TypeScript conversion
[\#13666](https://github.com/vector-im/riot-web/pull/13666)
* Update from Weblate
[\#13704](https://github.com/vector-im/riot-web/pull/13704)
* Replace favico.js dependency with simplified variant grown from it
[\#13649](https://github.com/vector-im/riot-web/pull/13649)
* Remove Electron packaging scripts
[\#13688](https://github.com/vector-im/riot-web/pull/13688)
* Fix postcss order to allow mixin variables to work
[\#13674](https://github.com/vector-im/riot-web/pull/13674)
* Pass screenAfterLogin through SSO in the callback url
[\#13650](https://github.com/vector-im/riot-web/pull/13650)
Changes in [1.6.2](https://github.com/vector-im/riot-web/releases/tag/v1.6.2) (2020-05-22)
==========================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v1.6.1...v1.6.2)
* Upgrade to React SDK 2.6.1
Changes in [1.6.1](https://github.com/vector-im/riot-web/releases/tag/v1.6.1) (2020-05-19)
==========================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v1.6.1-rc.1...v1.6.1)
* Upgrade to React SDK 2.6.0 and JS SDK 6.1.0
Changes in [1.6.1-rc.1](https://github.com/vector-im/riot-web/releases/tag/v1.6.1-rc.1) (2020-05-14)
====================================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v1.6.0...v1.6.1-rc.1)
* Upgrade to React SDK 2.6.0-rc.1 and JS SDK 6.1.0-rc.1
* Update from Weblate
[\#13673](https://github.com/vector-im/riot-web/pull/13673)
* Add notranslate class to matrixchat to prevent translation by Google
Translate
[\#13669](https://github.com/vector-im/riot-web/pull/13669)
* Added Anchor Link to the development of matrix sdk
[\#13638](https://github.com/vector-im/riot-web/pull/13638)
* Prefetch the formatting button mask svg images
[\#13631](https://github.com/vector-im/riot-web/pull/13631)
* use a different image in previews
[\#13488](https://github.com/vector-im/riot-web/pull/13488)
* Update from Weblate
[\#13625](https://github.com/vector-im/riot-web/pull/13625)
* Remove electron_app as we now have riot-desktop repo
[\#13544](https://github.com/vector-im/riot-web/pull/13544)
* add new images for PWA icons
[\#13556](https://github.com/vector-im/riot-web/pull/13556)
* Remove unused feature flag from config
[\#13504](https://github.com/vector-im/riot-web/pull/13504)
* Update from Weblate
[\#13486](https://github.com/vector-im/riot-web/pull/13486)
* Developer tool: convert rageshake error locations back to sourcecode
locations
[\#13357](https://github.com/vector-im/riot-web/pull/13357)
* App load tweaks, improve error pages
[\#13329](https://github.com/vector-im/riot-web/pull/13329)
* Tweak default device name to be more compact
[\#13465](https://github.com/vector-im/riot-web/pull/13465)
* Tweak default device name on macOS
[\#13460](https://github.com/vector-im/riot-web/pull/13460)
* Update docs with custom theming changes
[\#13406](https://github.com/vector-im/riot-web/pull/13406)
* Update from Weblate
[\#13395](https://github.com/vector-im/riot-web/pull/13395)
* Remove docs and config for invite only padlocks
[\#13374](https://github.com/vector-im/riot-web/pull/13374)
* Revert "Add font scaling labs setting."
[\#13351](https://github.com/vector-im/riot-web/pull/13351)
* Expand feature flag docs to cover additional release channels
[\#13341](https://github.com/vector-im/riot-web/pull/13341)
* Optimized image assets by recompressing without affecting quality.
[\#13034](https://github.com/vector-im/riot-web/pull/13034)
* Add font scaling labs setting.
[\#13199](https://github.com/vector-im/riot-web/pull/13199)
* Remove encrypted message search feature flag
[\#13325](https://github.com/vector-im/riot-web/pull/13325)
* Fix `default_federate` settting description
[\#13312](https://github.com/vector-im/riot-web/pull/13312)
* Clarify that the .well-known method for Jitsi isn't available yet
[\#13314](https://github.com/vector-im/riot-web/pull/13314)
* add config option to tsc resolveJsonModule
[\#13296](https://github.com/vector-im/riot-web/pull/13296)
* Fix dispatcher import to be extension agnostic
[\#13297](https://github.com/vector-im/riot-web/pull/13297)
* Document more config options in config.md (fixes #13089)
[\#13260](https://github.com/vector-im/riot-web/pull/13260)
* Fix tests post-js-sdk-filters change
[\#13295](https://github.com/vector-im/riot-web/pull/13295)
* Make Jitsi download script a JS script
[\#13227](https://github.com/vector-im/riot-web/pull/13227)
* Use matrix-react-sdk type extensions as a base
[\#13271](https://github.com/vector-im/riot-web/pull/13271)
* Allow Riot Web to randomly pick welcome backgrounds
[\#13235](https://github.com/vector-im/riot-web/pull/13235)
* Update cross-signing feature docs and document fallback procedures
[\#13224](https://github.com/vector-im/riot-web/pull/13224)
Changes in [1.6.0](https://github.com/vector-im/riot-web/releases/tag/v1.6.0) (2020-05-05)
==========================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v1.6.0-rc.6...v1.6.0)

View File

@@ -26,12 +26,10 @@
"defaultCountryCode": "GB",
"showLabsSettings": false,
"features": {
"feature_font_scaling": "labs",
"feature_pinning": "labs",
"feature_custom_status": "labs",
"feature_custom_tags": "labs",
"feature_state_counters": "labs",
"feature_irc_ui": "labs"
"feature_state_counters": "labs"
},
"default_federate": true,
"default_theme": "light",

View File

@@ -1,81 +0,0 @@
# App load order
Old slow flow:
![image](https://user-images.githubusercontent.com/2403652/73848963-00a2a080-4821-11ea-97d4-1200fc2638f3.png)
Current more parallel flow:
![image](https://user-images.githubusercontent.com/2403652/83146440-303a2900-a0ee-11ea-806b-4f53f039b957.png)
<details><summary>Code</summary>
<p>
<pre><code>
digraph G {
node [shape=box];
subgraph cluster_0 {
color=orange;
node [style=filled];
label = "index.ts";
entrypoint, s0, ready [shape=point];
rageshake, config, i18n, theme, skin, olm [shape=parallelogram];
mobile [shape=diamond, label="mobile"];
modernizr [shape=diamond];
redirect, incompatible [shape=egg];
entrypoint -> rageshake;
rageshake -> mobile [color=blue];
mobile -> s0 [label="No"];
mobile -> redirect [label="Yes"];
s0 -> platform;
s0 -> olm;
platform -> config;
config -> i18n [color=blue];
config -> theme [color=blue];
config -> skin [color=blue];
i18n -> modernizr [color=blue];
theme -> modernizr [color=blue];
skin -> modernizr [color=blue];
modernizr -> ready [label="Yes"];
modernizr -> incompatible [label="No"];
incompatible -> ready [label="user ignore"];
olm -> ready [color=red];
config -> ready [color=red];
skin -> ready [color=red];
theme -> ready [color=red];
i18n -> ready [color=red];
}
subgraph cluster_1 {
color = green;
node [style=filled];
label = "init.tsx";
ready -> loadApp;
loadApp -> matrixchat;
}
}
</code></pre>
</p>
</details>
Key:
+ Parallelogram: async/await task
+ Box: sync task
+ Diamond: conditional branch
+ Egg: user interaction
+ Blue arrow: async task is allowed to settle but allowed to fail
+ Red arrow: async task success is asserted
Notes:
+ A task begins when all its dependencies (arrows going into it) are fulfilled.
+ The success of setting up rageshake is never asserted, riot-web has a fallback path for running without IDB (and thus rageshake).
+ Everything is awaited to be settled before the Modernizr check, to allow it to make use of things like i18n if they are successful.
Underlying dependencies:
![image](https://user-images.githubusercontent.com/2403652/73848977-08624500-4821-11ea-9830-bb0317c41086.png)

View File

@@ -7,11 +7,6 @@ to `Settings->Labs`. This list is non-exhaustive and subject to change, chat in
**Be warned! Labs features are not finalised, they may be fragile, they may change, they may be
dropped. Ask in the room if you are unclear about any details here.**
## Font scaling (`feature_font_scaling`)
Enables font scaling options for accessibility. To alter the scale check the
appearance tab in settings.
## Message pinning (`feature_pinning`)
Allows you to pin messages in the room. To pin a message, use the 3 dots to the right of the message
@@ -111,15 +106,3 @@ adds an ability for end users to add themes themselves by using a URL to the JSO
theme definition.
For some sample themes, check out [aaronraimist/riot-web-themes](https://github.com/aaronraimist/riot-web-themes).
## New room list (`feature_new_room_list`) (in development)
A complete rewrite of the room list is underway to increase performance, stability,
and general usability. This is expected to take a while to complete and as such might
be missing critical features - please use at your own risk, though do report bugs!
## IRC message layout (`feature_irc_ui`)
Adds an option to change the message layout to an IRC style ` timestamp | avatar
| name | message `

View File

@@ -1,7 +1,7 @@
{
"name": "riot-web",
"productName": "Riot",
"version": "1.6.3",
"version": "1.6.0",
"description": "A feature-rich client for Matrix.org",
"author": "New Vector Ltd.",
"repository": {
@@ -58,10 +58,11 @@
},
"dependencies": {
"browser-request": "^0.3.3",
"favico.js": "^0.3.10",
"gfm.css": "^1.1.2",
"highlight.js": "^9.13.1",
"matrix-js-sdk": "6.2.0",
"matrix-react-sdk": "2.7.0",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
"matrix-react-sdk": "github:matrix-org/matrix-react-sdk#develop",
"olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
"postcss-easings": "^2.0.0",
"prop-types": "^15.7.2",
@@ -88,9 +89,7 @@
"@babel/preset-typescript": "^7.7.4",
"@babel/register": "^7.7.4",
"@babel/runtime": "^7.7.6",
"@types/flux": "^3.1.9",
"@types/modernizr": "^3.5.3",
"@types/node": "^12.12.41",
"@types/react": "16.9",
"@types/react-dom": "^16.9.4",
"autoprefixer": "^9.7.3",

View File

@@ -45,8 +45,6 @@ do
fi
done
./node_modules/matrix-js-sdk/release.sh -u vector-im -z "$orig_args"
release="${1#v}"
tag="v${release}"
prerelease=0
@@ -56,6 +54,16 @@ prerelease=0
# with a hyphen is a prerelease.
echo $release | grep -q '-' && prerelease=1
# bump Electron's package.json first
echo "electron yarn version"
cd electron_app
yarn version --no-git-tag-version --new-version "$release"
git commit package.json -m "$tag"
cd ..
./node_modules/matrix-js-sdk/release.sh -u vector-im -z "$orig_args"
if [ $prerelease -eq 0 ]
then
# For a release, reset SDK deps back to the `develop` branch.

View File

@@ -96,10 +96,19 @@ h1::after {
color: #2e2f32 !important;
}
.mx_ButtonHeadline {
margin-bottom: 14px;
}
.mx_ButtonLabel {
margin-left: 20px;
}
.mx_ButtonWrapperText {
font-size: 13px;
margin-bottom: 10px;
}
.mx_Header_title {
font-size: 24px;
font-weight: 600;
@@ -149,23 +158,6 @@ we don't have an account and should hide them. No account == no guest account ei
display: none;
}
.mx_ButtonRow.mx_WelcomePage_guestFunctions {
margin-top: 20px;
}
.mx_ButtonRow.mx_WelcomePage_guestFunctions > div {
margin: 0 auto;
}
@media only screen and (max-width: 480px) {
.mx_ButtonRow {
flex-direction: column;
}
.mx_ButtonRow > * {
margin: 0 0 10px 0;
}
}
</style>
<div class="mx_Parent">
@@ -190,8 +182,15 @@ we don't have an account and should hide them. No account == no guest account ei
<!-- BEGIN Ansible: Remove these lines when guest access is disabled -->
<div class="mx_ButtonRow mx_WelcomePage_guestFunctions">
<div>
<div class="mx_ButtonWrapperText">_t("Need help?")</div>
<a href="#/user/@riot-bot:matrix.org?action=chat" class="mx_ButtonParent mx_SecondaryButton mx_Button_iconHelp">
<div class="mx_ButtonLabel">_t("Chat with Riot Bot")</div>
</a>
</div>
<div>
<div class="mx_ButtonWrapperText">_t("Explore rooms")</div>
<a href="#/directory" class="mx_ButtonParent mx_SecondaryButton mx_Button_iconRoomDirectory">
<div class="mx_ButtonLabel">_t("Explore rooms")</div>
<div class="mx_ButtonLabel">_t("Room Directory")</div>
</a>
</div>
</div>

View File

@@ -10,7 +10,7 @@
"https://scalar-staging.vector.im/api",
"https://scalar-staging.riot.im/scalar/api"
],
"hosting_signup_link": "https://modular.im/services/matrix-hosting-riot?utm_source=riot-web&utm_medium=web",
"hosting_signup_link": "https://modular.im/?utm_source=riot-web&utm_medium=web",
"bug_report_endpoint_url": "https://riot.im/bugreports/submit",
"features": {
},

View File

@@ -10,10 +10,9 @@
"https://scalar-staging.vector.im/api",
"https://scalar-staging.riot.im/scalar/api"
],
"hosting_signup_link": "https://modular.im/services/matrix-hosting-riot?utm_source=riot-web&utm_medium=web",
"hosting_signup_link": "https://modular.im/?utm_source=riot-web&utm_medium=web",
"bug_report_endpoint_url": "https://riot.im/bugreports/submit",
"features": {
"feature_font_scaling": "labs",
"feature_pinning": "labs",
"feature_custom_status": "labs",
"feature_custom_tags": "labs",
@@ -23,9 +22,7 @@
"feature_dm_verification": "labs",
"feature_bridge_state": "labs",
"feature_presence_in_room_list": "labs",
"feature_custom_themes": "labs",
"feature_new_room_list": "labs",
"feature_irc_ui": "labs"
"feature_custom_themes": "labs"
},
"piwik": {
"url": "https://piwik.riot.im/",

170
scripts/electron-package.sh Executable file
View File

@@ -0,0 +1,170 @@
#!/bin/bash
usage() {
echo "Usage: $0 -v <version> -d <config directory> [-n]"
echo
echo "version: commit-ish to check out and build"
echo "config directory: a path to a directory containing"
echo "config.json, a json config file to ship with the build"
echo "and env.sh, a file to source environment variables"
echo "from."
echo "-n: build with no config file."
echo
echo "The update_base_url value from config.json is used to set up auto-update."
echo
echo "Environment variables:"
echo " OSSLSIGNCODE_SIGNARGS: Arguments to pass to osslsigncode when signing"
echo " NOTARIZE_APPLE_ID: Apple ID to use for notarisation. The password for"
echo " this account must be set in NOTARIZE_CREDS in the keychain."
}
confdir=
version=
skipcfg=0
while getopts "d:v:n" opt; do
case $opt in
d)
confdir=$OPTARG
;;
v)
version=$OPTARG
;;
n)
skipcfg=1
;;
\?)
echo "Invalid option: -$OPTARG" >&2
usage
exit
;;
esac
done
if [ -z "$version" ]; then
echo "No version supplied"
usage
exit
fi
conffile="$confdir/config.json"
if [ -z "$conffile" ] && [ "$skipcfg" = 0 ]; then
echo "No config file given. Use -c to supply a config file or"
echo "-n to build with no config file (and no auto update)."
exit
fi
if [ -n "$conffile" ]; then
update_base_url=`jq -r .update_base_url $conffile`
if [ -z "$update_base_url" ]; then
echo "No update URL supplied. Use update_base_url: null if you really"
echo "want a build with no auto-update."
usage
exit
fi
# Make sure the base URL ends in a slash if it doesn't already
update_base_url=`echo $update_base_url | sed -e 's#\([^\/]\)$#\1\/#'`
fi
if [ ! -f package.json ]; then
echo "No package.json found. This script must be run from"
echo "the riot-web directory."
exit
fi
[ -f "$confdir/env.sh" ] && . "$confdir/env.sh"
if [ -z "$NOTARIZE_APPLE_ID" ]; then
echo "NOTARIZE_APPLE_ID is not set"
exit
fi
osslsigncode -h 2> /dev/null
if [ $? -ne 255 ]; then # osslsigncode exits with 255 after printing usage...
echo "osslsigncode not found"
exit
fi
# Test that altool can get its credentials for notarising the mac app
xcrun altool -u "$NOTARIZE_APPLE_ID" -p '@keychain:NOTARIZE_CREDS' --list-apps || exit
# Get the token password: we'll need it later, but get it now so we fail early if it's not there
token_password=`security find-generic-password -s riot_signing_token -w`
if [ $? -ne 0 ]; then
echo "riot_signing_token not found in keychain"
exit
fi
set -e
echo "Building $version using Update base URL $update_base_url"
projdir=`pwd`
builddir=`mktemp -d 2>/dev/null || mktemp -d -t 'buildtmp'`
pushd "$builddir"
git clone "$projdir" .
git checkout "$version"
# Figure out what version we're building
vername=`jq -r .version package.json`
if [ -n "$conffile" ]; then
popd
cp "$conffile" "$builddir/"
pushd "$builddir"
fi
# We use Git branch / commit dependencies for some packages, and Yarn seems
# to have a hard time getting that right. See also
# https://github.com/yarnpkg/yarn/issues/4734. As a workaround, we clean the
# global cache here to ensure we get the right thing.
yarn cache clean
yarn install
yarn build:electron
popd
distdir="$builddir/electron_app/dist"
pubdir="$projdir/electron_app/pub"
rm -r "$pubdir" || true
mkdir -p "$pubdir"
rm -r "$projdir/electron_app/dist" || true
mkdir -p "$projdir/electron_app/dist"
# Install packages: what the user downloads the first time,
# (DMGs for mac, exe installer for windows)
mkdir -p "$pubdir/install/macos"
cp $distdir/*.dmg "$pubdir/install/macos/"
mkdir -p "$pubdir/install/win32/ia32/"
cp $distdir/squirrel-windows-ia32/*.exe "$pubdir/install/win32/ia32/"
mkdir -p "$pubdir/install/win32/x64/"
cp $distdir/squirrel-windows/*.exe "$pubdir/install/win32/x64/"
# Packages for auto-update
mkdir -p "$pubdir/update/macos"
cp $distdir/*-mac.zip "$pubdir/update/macos/"
echo "$vername" > "$pubdir/update/macos/latest"
mkdir -p "$pubdir/update/win32/ia32/"
cp $distdir/squirrel-windows-ia32/*.nupkg "$pubdir/update/win32/ia32/"
cp $distdir/squirrel-windows-ia32/RELEASES "$pubdir/update/win32/ia32/"
mkdir -p "$pubdir/update/win32/x64/"
cp $distdir/squirrel-windows/*.nupkg "$pubdir/update/win32/x64/"
cp $distdir/squirrel-windows/RELEASES "$pubdir/update/win32/x64/"
# Move the deb to the main project dir's dist folder
# (just the 64 bit one - the 32 bit one still gets built because
# it's one arch argument for all platforms and we still want 32 bit
# windows, but 32 bit linux is unsupported as of electron 4 and no
# longer appears to work).
cp $distdir/*_amd64.deb "$projdir/electron_app/dist/"
rm -rf "$builddir"
echo "$pubdir can now be hosted on your web server."
echo "deb archives are in electron_app/dist/ - these should be added into your debian repository"

View File

@@ -0,0 +1,30 @@
const { notarize } = require('electron-notarize');
exports.default = async function(context) {
const { electronPlatformName, appOutDir } = context;
if (electronPlatformName === 'darwin') {
const appName = context.packager.appInfo.productFilename;
// We get the password from keychain. The keychain stores
// user IDs too, but apparently altool can't get the user ID
// from the keychain, so we need to get it from the environment.
const userId = process.env.NOTARIZE_APPLE_ID;
if (userId === undefined) {
console.warn(
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" +
"! Skipping macOS notarisation. !\n" +
"! User ID not found, set NOTARIZE_APPLE_ID. !\n" +
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
);
return;
}
console.log("Notarising macOS app. This may be some time.");
return await notarize({
appBundleId: 'im.riot.app',
appPath: `${appOutDir}/${appName}.app`,
appleId: userId,
appleIdPassword: '@keychain:NOTARIZE_CREDS',
});
}
};

View File

@@ -0,0 +1,77 @@
const { exec, execFile } = require('child_process');
const fs = require('fs');
const path = require('path');
const shellescape = require('shell-escape');
exports.default = async function(options) {
const inPath = options.path;
const appOutDir = path.dirname(inPath);
// get the token passphrase from the keychain
let tokenPassphrase;
try {
tokenPassphrase = await new Promise((resolve, reject) => {
execFile(
'security',
['find-generic-password', '-s', 'riot_signing_token', '-w'],
{},
(err, stdout) => {
if (err) {
reject(err);
} else {
resolve(stdout.trim());
}
},
);
});
} catch (err) {
console.warn(
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" +
"! Skipping Windows signing. !\n" +
"! Signing token not found in keychain. !\n" +
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
);
return;
}
return new Promise((resolve, reject) => {
let cmdLine = 'osslsigncode sign ';
if (process.env.OSSLSIGNCODE_SIGNARGS) {
cmdLine += process.env.OSSLSIGNCODE_SIGNARGS + ' ';
}
const tmpFile = path.join(
appOutDir,
'tmp_' + Math.random().toString(36).substring(2, 15) + '.exe',
);
const args = [
'-h', options.hash,
'-pass', tokenPassphrase,
'-in', inPath,
'-out', tmpFile,
];
if (options.isNest) args.push('-nest');
cmdLine += shellescape(args);
let signStdout;
const signproc = exec(cmdLine, {}, (error, stdout) => {
signStdout = stdout;
});
signproc.on('exit', (code) => {
if (code !== 0) {
console.log("Running", cmdLine);
console.log(signStdout);
console.error("osslsigncode failed with code " + code);
reject("osslsigncode failed with code " + code);
return;
}
fs.rename(tmpFile, inPath, (err) => {
if (err) {
console.error("Error renaming file", err);
reject(err);
} else {
resolve();
}
});
});
});
};

View File

@@ -24,18 +24,5 @@ declare global {
// electron-only
ipcRenderer: any;
// opera-only
opera: any;
// https://developer.mozilla.org/en-US/docs/Web/API/InstallTrigger
InstallTrigger: any;
}
}
// add method which is missing from the node typing
declare module "url" {
interface Url {
format(): string;
}
}

View File

@@ -1,255 +0,0 @@
/*
Copyright 2020 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
interface IParams {
// colour parameters
bgColor: string;
textColor: string;
// font styling parameters
fontFamily: string;
fontWeight: "normal" | "italic" | "bold" | "bolder" | "lighter" | number;
// positioning parameters
isUp: boolean;
isLeft: boolean;
}
const defaults: IParams = {
bgColor: "#d00",
textColor: "#fff",
fontFamily: "sans-serif", // Arial,Verdana,Times New Roman,serif,sans-serif,...
fontWeight: "bold", // normal,italic,oblique,bold,bolder,lighter,100,200,300,400,500,600,700,800,900
isUp: false,
isLeft: false,
};
// Allows dynamic rendering of a circular badge atop the loaded favicon
// supports colour, font and basic positioning parameters.
// Based upon https://github.com/ejci/favico.js/blob/master/favico.js [MIT license]
export default class Favicon {
private readonly browser = {
ff: typeof window.InstallTrigger !== "undefined",
opera: !!window.opera || navigator.userAgent.includes("Opera"),
};
private readonly params: IParams;
private readonly canvas: HTMLCanvasElement;
private readonly baseImage: HTMLImageElement;
private context: CanvasRenderingContext2D;
private icons: HTMLLinkElement[];
private isReady: boolean = false;
// callback to run once isReady is asserted, allows for a badge to be queued for when it can be shown
private readyCb = () => {};
constructor(params: Partial<IParams> = {}) {
this.params = {...defaults, ...params};
this.icons = Favicon.getIcons();
// create work canvas
this.canvas = document.createElement("canvas");
// create clone of favicon as a base
this.baseImage = document.createElement("img");
const lastIcon = this.icons[this.icons.length - 1];
if (lastIcon.hasAttribute("href")) {
this.baseImage.setAttribute("crossOrigin", "anonymous");
this.baseImage.onload = () => {
// get height and width of the favicon
this.canvas.height = (this.baseImage.height > 0) ? this.baseImage.height : 32;
this.canvas.width = (this.baseImage.width > 0) ? this.baseImage.width : 32;
this.context = this.canvas.getContext("2d");
this.ready();
};
this.baseImage.setAttribute("src", lastIcon.getAttribute("href"));
} else {
this.canvas.height = this.baseImage.height = 32;
this.canvas.width = this.baseImage.width = 32;
this.context = this.canvas.getContext("2d");
this.ready();
}
}
private reset() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.context.drawImage(this.baseImage, 0, 0, this.canvas.width, this.canvas.height);
}
private options(n: number | string, params: IParams) {
const opt = {
n: ((typeof n) === "number") ? Math.abs(n as number | 0) : n,
len: ("" + n).length,
// badge positioning constants as percentages
x: 0.4,
y: 0.4,
w: 0.6,
h: 0.6,
};
// apply positional transformations
if (params.isUp) {
if (opt.y < 0.6) {
opt.y = opt.y - 0.4;
} else {
opt.y = opt.y - 2 * opt.y + (1 - opt.w);
}
}
if (params.isLeft) {
if (opt.x < 0.6) {
opt.x = opt.x - 0.4;
} else {
opt.x = opt.x - 2 * opt.x + (1 - opt.h);
}
}
// scale the position to the canvas
opt.x = this.canvas.width * opt.x;
opt.y = this.canvas.height * opt.y;
opt.w = this.canvas.width * opt.w;
opt.h = this.canvas.height * opt.h;
return opt;
}
private circle(n: number | string, opts?: Partial<IParams>) {
const params = {...this.params, ...opts};
const opt = this.options(n, params);
let more = false;
if (opt.len === 2) {
opt.x = opt.x - opt.w * 0.4;
opt.w = opt.w * 1.4;
more = true;
} else if (opt.len >= 3) {
opt.x = opt.x - opt.w * 0.65;
opt.w = opt.w * 1.65;
more = true;
}
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.context.drawImage(this.baseImage, 0, 0, this.canvas.width, this.canvas.height);
this.context.beginPath();
const fontSize = Math.floor(opt.h * (opt.n > 99 ? 0.85 : 1)) + "px";
this.context.font = `${params.fontWeight} ${fontSize} ${params.fontFamily}`;
this.context.textAlign = "center";
if (more) {
this.context.moveTo(opt.x + opt.w / 2, opt.y);
this.context.lineTo(opt.x + opt.w - opt.h / 2, opt.y);
this.context.quadraticCurveTo(opt.x + opt.w, opt.y, opt.x + opt.w, opt.y + opt.h / 2);
this.context.lineTo(opt.x + opt.w, opt.y + opt.h - opt.h / 2);
this.context.quadraticCurveTo(opt.x + opt.w, opt.y + opt.h, opt.x + opt.w - opt.h / 2, opt.y + opt.h);
this.context.lineTo(opt.x + opt.h / 2, opt.y + opt.h);
this.context.quadraticCurveTo(opt.x, opt.y + opt.h, opt.x, opt.y + opt.h - opt.h / 2);
this.context.lineTo(opt.x, opt.y + opt.h / 2);
this.context.quadraticCurveTo(opt.x, opt.y, opt.x + opt.h / 2, opt.y);
} else {
this.context.arc(opt.x + opt.w / 2, opt.y + opt.h / 2, opt.h / 2, 0, 2 * Math.PI);
}
this.context.fillStyle = params.bgColor;
this.context.fill();
this.context.closePath();
this.context.beginPath();
this.context.stroke();
this.context.fillStyle = params.textColor;
if ((typeof opt.n) === "number" && opt.n > 999) {
const count = ((opt.n > 9999) ? 9 : Math.floor(opt.n as number / 1000)) + "k+";
this.context.fillText(count, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2));
} else {
this.context.fillText("" + opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15));
}
this.context.closePath();
}
private ready() {
if (this.isReady) return;
this.isReady = true;
this.readyCb();
}
private setIcon(canvas) {
setImmediate(() => {
this.setIconSrc(canvas.toDataURL("image/png"));
});
}
private setIconSrc(url) {
// if is attached to fav icon
if (this.browser.ff || this.browser.opera) {
// for FF we need to "recreate" element, attach to dom and remove old <link>
const old = this.icons[this.icons.length - 1];
const newIcon = window.document.createElement("link");
this.icons = [newIcon];
newIcon.setAttribute("rel", "icon");
newIcon.setAttribute("type", "image/png");
window.document.getElementsByTagName("head")[0].appendChild(newIcon);
newIcon.setAttribute("href", url);
if (old.parentNode) {
old.parentNode.removeChild(old);
}
} else {
this.icons.forEach(icon => {
icon.setAttribute("href", url);
});
}
}
public badge(content: number | string, opts?: Partial<IParams>) {
if (!this.isReady) {
this.readyCb = () => {
this.badge(content, opts);
}
return;
}
if (typeof content === "string" || content > 0) {
this.circle(content, opts);
} else {
this.reset();
}
this.setIcon(this.canvas);
}
private static getLinks() {
const icons: HTMLLinkElement[] = [];
const links = window.document.getElementsByTagName("head")[0].getElementsByTagName("link");
for (let i = 0; i < links.length; i++) {
if ((/(^|\s)icon(\s|$)/i).test(links[i].getAttribute("rel"))) {
icons.push(links[i]);
}
}
return icons;
}
private static getIcons() {
// get favicon link elements
let elms = Favicon.getLinks();
if (elms.length === 0) {
elms = [window.document.createElement("link")];
elms[0].setAttribute("rel", "icon");
window.document.getElementsByTagName("head")[0].appendChild(elms[0]);
}
elms.forEach(item => {
item.setAttribute("type", "image/png");
});
return elms;
}
}

View File

@@ -31,5 +31,8 @@
"Decentralised, encrypted chat &amp; collaboration powered by [matrix]": "Decentralised, encrypted chat &amp; collaboration powered by [matrix]",
"Sign In": "Sign In",
"Create Account": "Create Account",
"Explore rooms": "Explore rooms"
"Need help?": "Need help?",
"Chat with Riot Bot": "Chat with Riot Bot",
"Explore rooms": "Explore rooms",
"Room Directory": "Room Directory"
}

View File

@@ -26,15 +26,5 @@
"Open user settings": "Ireki erabiltzailearen ezarpenak",
"Missing indexeddb worker script!": "indexeddb langile scripta falta da!",
"Unable to load config file: please refresh the page to try again.": "Ezin izan da konfigurazio fitxategia kargatu: Saiatu orria birkargatzen.",
"Previous/next recently visited room or community": "Berriki bisitatutako aurreko/hurrengo gela edo komunitatea",
"Riot Desktop (%(platformName)s)": "Riot Desktop (%(platformName)s)",
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
"Unsupported browser": "Onartu gabeko nabigatzailea",
"Your browser can't run Riot": "Zure nabigatzaileak ezin du Riot abiatu",
"Riot uses advanced browser features which aren't supported by your current browser.": "Riotek zure oraingo nabigatzailean erabilgarri ez dauden ezaugarri aurreratuak erabiltzen ditu .",
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Instalatu <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, edo <safariLink>Safari</safariLink> esperientzia hobe baterako.",
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Zure oraingo nabigatzailea erabiltzen jarraitu dezakezu, baina ezaugarri batzuk agian ez dute funtzionatuko eta itxura desegokia izan daiteke.",
"I understand the risks and wish to continue": "Arriskuak ulertzen ditut eta jarraitu nahi dut",
"Go to Riot.im": "Joan Riot.im gunera",
"Failed to start": "Huts egin du abiatzean"
"Previous/next recently visited room or community": "Berriki bisitatutako aurreko/hurrengo gela edo komunitatea"
}

View File

@@ -1,7 +1,7 @@
{
"Dismiss": "Hylkää",
"Unknown device": "Tuntematon laite",
"Welcome to Riot.im": "Tervetuloa Riot.im-sovellukseen",
"Welcome to Riot.im": "Tervetuloa Riot.im-palveluun",
"Custom Server Options": "Palvelinasetukset",
"Riot Desktop on %(platformName)s": "Riot Desktop, %(platformName)s",
"You need to be using HTTPS to place a screen-sharing call.": "Sinun täytyy käyttää HTTPS-yhteyttä, jotta voit jakaa ruudun puhelussa.",
@@ -22,18 +22,5 @@
"Your Riot configuration contains invalid JSON. Please correct the problem and reload the page.": "Riot-asetuksissasi on virheellistä JSONia. Korjaa ongelma ja lataa sivu uudelleen.",
"The message from the parser is: %(message)s": "Viesti jäsentimeltä: %(message)s",
"Invalid JSON": "Virheellinen JSON",
"Missing indexeddb worker script!": "Indexeddb-suorittajan skripti puuttuu!",
"Unable to load config file: please refresh the page to try again.": "Asetustiedostoa ei voi ladata. Yritä uudelleen lataamalla sivu uudelleen.",
"Open user settings": "Avaa käyttäjäasetukset",
"Previous/next recently visited room or community": "Edellinen/seuraava hiljattain vierailtu huone tai yhteisö",
"Riot Desktop (%(platformName)s)": "Riot Desktop (%(platformName)s)",
"Go to your browser to complete Sign In": "Tee kirjautuminen loppuun selaimessasi",
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
"Unsupported browser": "Selainta ei tueta",
"Your browser can't run Riot": "Riot ei toimi selaimellasi",
"Riot uses advanced browser features which aren't supported by your current browser.": "Riot käyttää edistyneitä selaimen ominaisuuksia, joita nykyinen selaimesi ei tue.",
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Asenna <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink> tai <safariLink>Safari</safariLink>, jotta kaikki toimii parhaiten.",
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Voit käyttää edelleen nykyistä selaintasi, mutta jotkut tai kaikki ominaisuudet eivät ehkä toimi ja sovelluksen ulkoasu voi olla virheellinen.",
"I understand the risks and wish to continue": "Ymmärrän riskit ja haluan jatkaa",
"Failed to start": "Käynnistys ei onnistunut"
"Missing indexeddb worker script!": "Indexeddb-suorittajan skripti puuttuu!"
}

View File

@@ -10,7 +10,7 @@
"Decentralised, encrypted chat &amp; collaboration powered by [matrix]": "Conversas e colaboración descentralizada e cifrada grazas a [matrix]",
"Chat with Riot Bot": "Conversa co bot de Riot",
"You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use Riot with an existing Matrix account on a different homeserver.": "Podes usar as opcións de servidor personalizado para iniciar sesión en outros servidores Matrix especificando unha dirección diferente de servidor doméstico. Con esto podes usar Riot cunha conta Matrix existente noutro servidor doméstico.",
"Sign In": "Conectar",
"Sign In": "Entrar",
"Create Account": "Crear conta",
"Need help?": "¿Precisas axuda?",
"Explore rooms": "Explorar salas",
@@ -18,23 +18,8 @@
"Your Riot configuration contains invalid JSON. Please correct the problem and reload the page.": "A configuración de Riot contén JSON non válido. Corrixe o problema e recarga a páxina.",
"The message from the parser is: %(message)s": "A mensaxe desde o intérprete é: %(message)s",
"Invalid JSON": "JSON non válido",
"Your Riot is misconfigured": "O teu Riot está mal configurado",
"Your Riot is misconfigured": "Riot está mal configurado",
"Unexpected error preparing the app. See console for details.": "Fallo non agardado ao preparar a app. Detalles na consola.",
"Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Configuración non válida: só se pode indicar un de default_server_config, default_server_name, ou default_hs_url.",
"Invalid configuration: no default server specified.": "Configuración non válida: non se indicou servidor por omisión.",
"Missing indexeddb worker script!": "Falta o script indexeddb!",
"Unable to load config file: please refresh the page to try again.": "Non se cargou o ficheiro de configuración: actualiza a páxina para reintentalo.",
"Open user settings": "Abrir axustes do usuario",
"Previous/next recently visited room or community": "Anterior/seguinte sala ou comunidade recentes",
"Riot Desktop (%(platformName)s)": "Riot Desktop (%(platformName)s)",
"Go to your browser to complete Sign In": "Abre o navegador para realizar a Conexión",
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
"Unsupported browser": "Navegador non soportado",
"Your browser can't run Riot": "O teu navegador non pode executar Riot",
"Riot uses advanced browser features which aren't supported by your current browser.": "Riot utiliza funcións avanzadas dos navegadores que o teu actual non soporta.",
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Instala <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, ou <safariLink>Safari</safariLink> para ter unha mellor experiencia.",
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Podes continuar co teu navegador, pero algunhas características poderían non funcionar e o aspecto da aplicación podería non ser o correcto.",
"I understand the risks and wish to continue": "Entendo os riscos e desexo continuar",
"Go to Riot.im": "Ir a Riot.im",
"Failed to start": "Fallou o inicio"
"Invalid configuration: no default server specified.": "Configuración non válida: non se indicou servidor por omisión."
}

View File

@@ -21,19 +21,5 @@
"Create Account": "계정 만들기",
"Need help?": "도움이 필요합니까?",
"Explore rooms": "방 검색",
"Room Directory": "방 목록",
"Unable to load config file: please refresh the page to try again.": "설정 파일을 불러오는 데 실패: 페이지를 새로고침한 후에 다시 시도해 주십시오.",
"Open user settings": "사용자 설정 열기",
"Previous/next recently visited room or community": "최근에 방문한 이전/다음 방 또는 커뮤니티",
"Riot Desktop (%(platformName)s)": "Riot 데스크탑 (%(platformName)s)",
"Go to your browser to complete Sign In": "로그인을 완료하려면 브라우저로 이동해주세요",
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
"Unsupported browser": "지원되지 않는 브라우저",
"Your browser can't run Riot": "사용중이신 브라우저는 Riot을 실행할 수 없습니다",
"Riot uses advanced browser features which aren't supported by your current browser.": "Riot은 현재 사용중이신 브라우저에서는 지원하지 않는 고급 브라우저 기능을 사용합니다.",
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "최상의 경험을 위해 <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, 또는 <safariLink>Safari</safariLink>를 설치해주세요.",
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "현재 사용중이신 브라우저를 계속 사용하셔도 됩니다, 다만 일부 기능들이 작동하지 않을 수 있으며 애플리케이션이 잘못돼 보일 수 있습니다.",
"I understand the risks and wish to continue": "위험하다는 것을 이해했으며 계속하고 싶습니다",
"Go to Riot.im": "Riot.im으로 가기",
"Failed to start": "시작 실패"
"Room Directory": "방 목록"
}

View File

@@ -10,7 +10,7 @@
"Dismiss": "Atmesti",
"Decentralised, encrypted chat &amp; collaboration powered by [matrix]": "Decentralizuoti, šifruoti pokalbiai ir bendradarbiavimas, veikiantis su [matrix]",
"Sign In": "Prisijungti",
"Create Account": "Sukurti Paskyrą",
"Create Account": "Sukurti paskyrą",
"Need help?": "Reikia pagalbos?",
"Explore rooms": "Žvalgyti kambarius",
"Room Directory": "Kambarių katalogas",
@@ -21,20 +21,7 @@
"Unexpected error preparing the app. See console for details.": "Netikėta klaida ruošiant programą. Norėdami sužinoti daugiau detalių, žiūrėkite konsolę.",
"Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Klaidinga konfigūracija: galima nurodyti tik vieną iš default_server_config, default_server_name, arba default_hs_url.",
"Invalid configuration: no default server specified.": "Klaidinga konfigūracija: nenurodytas numatytasis serveris.",
"You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use Riot with an existing Matrix account on a different homeserver.": "Jūs galite naudoti pasirinktinius serverio nustatymus, kad prisijungtumėte prie kitų Matrix serverių, nurodydami kito serverio URL. Tai leidžia jums naudotis Riot su kitame serveryje esančia Matrix paskyra.",
"You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use Riot with an existing Matrix account on a different homeserver.": "Jūs galite naudoti pasirinktinius serverio nustatymus, kad prisijungtumėte prie kitų Matrix serverių, nurodydami kito serverio URL. Tai leidžia jums naudotis Riot su esama Matrix paskyra kitame serveryje.",
"Go to your browser to complete Sign In": "Norėdami užbaigti prisijungimą, eikite į naršyklę",
"Open user settings": "Atverti vartotojo nustatymus",
"Missing indexeddb worker script!": "Trūksta indexeddb worker skripto!",
"Unable to load config file: please refresh the page to try again.": "Nepavyko įkelti konfigūracijos failo: iš naujo užkraukite puslapį ir bandykite dar kartą.",
"Previous/next recently visited room or community": "Ankstesnis/sekantis neseniai lankytas kambarys ar bendruomenė",
"Riot Desktop (%(platformName)s)": "Riot Kompiuteriui (%(platformName)s)",
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
"Unsupported browser": "Nepalaikoma naršyklė",
"Your browser can't run Riot": "Jūsų naršyklė negali paleisti Riot",
"Riot uses advanced browser features which aren't supported by your current browser.": "Riot naudoja išplėstines funkcijas, kurių jūsų dabartinė naršyklė nepalaiko.",
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Riot geriausiai veikia su <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, arba <safariLink>Safari</safariLink> naršyklėmis.",
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Jūs galite toliau naudotis savo dabartine naršykle, bet kai kurios arba visos funkcijos gali neveikti ir programos išvaizda bei sąsaja gali būti neteisingai rodoma.",
"I understand the risks and wish to continue": "Suprantu šią riziką ir noriu tęsti",
"Go to Riot.im": "Eiti į Riot.im",
"Failed to start": "Nepavyko paleisti"
"Open user settings": "Atverti vartotojo nustatymus"
}

View File

@@ -21,16 +21,5 @@
"Your Riot configuration contains invalid JSON. Please correct the problem and reload the page.": "Jūsu Riot konfigurācijā ir nederīgs JSON. Lūdzu, izlabojiet problēmu un ielādējiet lapu atkārtoti.",
"The message from the parser is: %(message)s": "Ziņojums no parsētāja ir: %(message)s",
"Invalid JSON": "Nederīgs JSON",
"Your Riot is misconfigured": "Jūsu Riot ir nepareizi konfigurēts",
"Unable to load config file: please refresh the page to try again.": "Neizdevās ielādēt config datni: lūdzu pārlādē lapu lai mēģinātu vēlreiz.",
"Open user settings": "Atver lietotāja iestatījumus",
"Go to your browser to complete Sign In": "Aizej uz savu pārlūku lai pabeigtu Piekļuvi",
"Unsupported browser": "Neatbalstīts pārlūks",
"Your browser can't run Riot": "Tavs pārlūks nevar palaist Riot",
"Riot uses advanced browser features which aren't supported by your current browser.": "",
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Lūdzu instalē <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, vai <safariLink>Safari</safariLink> priekš labākās pieredzes.",
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Tu vari turpināt izmantot savu pašreizējo pārlūku, bet dažas vai visas funkcijas nestrādās, un lietotnes izskats var būt nepareizs.",
"I understand the risks and wish to continue": "Es pieņemu riskus un vēlos turpināt",
"Go to Riot.im": "Ej uz Riot.im",
"Failed to start": "Neizdevās palaist"
"Your Riot is misconfigured": "Jūsu Riot ir nepareizi konfigurēts"
}

View File

@@ -17,8 +17,8 @@
"Room Directory": "Gesprekscatalogus",
"Unexpected error preparing the app. See console for details.": "Er is een onverwachte fout opgetreden bij het voorbereiden van de app. Zie de console voor details.",
"Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Configuratiefout: kan slechts één van default_server_config, default_server_name, of default_hs_url opgeven.",
"Invalid configuration: no default server specified.": "Configuratie ongeldig: geen standaardserver opgegeven.",
"Your Riot is misconfigured": "Uw Riot is verkeerd geconfigureerd",
"Invalid configuration: no default server specified.": "Configuratiefout: geen standaardserver opgegeven.",
"Your Riot is misconfigured": "Uw Riot is onjuist geconfigureerd",
"Your Riot configuration contains invalid JSON. Please correct the problem and reload the page.": "Uw Riot-configuratie bevat ongeldige JSON. Corrigeer het probleem en herlaad de pagina.",
"The message from the parser is: %(message)s": "De ontleder meldt: %(message)s",
"Invalid JSON": "Ongeldige JSON",

View File

@@ -14,16 +14,5 @@
"Create Account": "Înregistare",
"Need help?": "Ai nevoie de ajutor?",
"Explore rooms": "Explorează camerele",
"Room Directory": "Lista de camere",
"Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Configuratie invalida: se poate specifica doar una dintre default_server_config, default_server_name, or default_hs_url.",
"Your Riot is misconfigured": "Aplicatia ta Riot e gresit configurata",
"Invalid JSON": "JSON invalid",
"Riot Desktop (%(platformName)s)": "Riot Desktop (%(platformName)s)",
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
"Unsupported browser": "Acest browser nu este suportat",
"Your browser can't run Riot": "Browserul tau nu poate rula Riot",
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Instalati va rog <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> pentru o experienta mai buna.",
"I understand the risks and wish to continue": "Inteleg riscul si doresc sa continui",
"Go to Riot.im": "Acceseaza Riot.im",
"Failed to start": "Nu reuseste sa porneasca"
"Room Directory": "Lista de camere"
}

View File

@@ -26,15 +26,5 @@
"Unable to load config file: please refresh the page to try again.": "Nemožno načítať konfiguračný súbor: prosím, obnovte stránku a skúste to znova.",
"Open user settings": "Otvoriť používateľské nastavenia",
"Previous/next recently visited room or community": "Predchádzajúca/ďalšia nedávno navštívená miestnosť alebo komunita",
"Go to your browser to complete Sign In": "Prejdite do prehliadača a dokončite prihlásenie",
"Riot Desktop (%(platformName)s)": "Riot Desktop (%(platformName)s)",
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
"Unsupported browser": "Nepodporovaný prehliadač",
"Your browser can't run Riot": "Váš prehliadač nerozbehne Riot",
"Riot uses advanced browser features which aren't supported by your current browser.": "Riot používa komplexnejšie funkcie prehliadača, ktoré nie sú podporované vo vašom prehliadači.",
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Prosím, nainštalujte si <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink> alebo <safariLink>Safari</safariLink> pre najlepší zážitok.",
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Môžete naďalej používať váš súčasný prehliadač, ale niektoré alebo všetky funkcie nemusia fungovať a zážitok z aplikácie nemusí byť optimálny.",
"I understand the risks and wish to continue": "Rozumiem riziku a chcem pokračovať",
"Go to Riot.im": "Prejsť na Riot.im",
"Failed to start": "Zapnutie zlyhalo"
"Go to your browser to complete Sign In": "Prejdite do prehliadača a dokončite prihlásenie"
}

View File

@@ -35,6 +35,5 @@
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Mund të vazhdoni të përdorni shfletuesin tuaj të tanishëm, por disa ose krejt veçoritë mund të mos funksionojnë dhe pamja dhe ndjesitë prej aplikacionit të mos jenë të sakta.",
"I understand the risks and wish to continue": "I kuptoj rreziqet dhe dëshiroj të vazhdoj",
"Go to Riot.im": "Shko te Riot.im",
"Failed to start": "Su arrit të nisej",
"Missing indexeddb worker script!": "Mungon programth worker-i indexeddb-je!"
"Failed to start": "Su arrit të nisej"
}

View File

@@ -15,7 +15,6 @@
<link rel="manifest" href="manifest.json">
<meta name="referrer" content="no-referrer">
<link rel="shortcut icon" href="<%= require('../../res/vector-icons/favicon.ico') %>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="apple-mobile-web-app-title" content="Riot">
<meta name="application-name" content="Riot">
<meta name="msapplication-TileColor" content="#da532c">
@@ -52,7 +51,7 @@
</head>
<body style="height: 100%; margin: 0;" data-vector-indexeddb-worker-script="<%= htmlWebpackPlugin.files.chunks['indexeddb-worker'].entry %>">
<noscript>Sorry, Riot requires JavaScript to be enabled.</noscript> <!-- TODO: Translate this? -->
<section id="matrixchat" style="height: 100%; overflow: auto;" class="notranslate"></section>
<section id="matrixchat" style="height: 100%; overflow: auto;"></section>
<script src="<%= htmlWebpackPlugin.files.chunks['bundle'].entry %>"></script>
<!-- Legacy supporting Prefetch images -->

View File

@@ -78,6 +78,70 @@ function checkBrowserFeatures() {
return featureComplete;
}
/**
* Monkey patch some browser methods to work around a fundamental
* incompatability between React and any browser extension or anything
* else that manipulates the DOM.
*
* React issue: https://github.com/facebook/react/issues/11538
* Chromium issue: https://bugs.chromium.org/p/chromium/issues/detail?id=872770
*
* The workaround here is inspired by the one in a comment on the React bug
* (https://github.com/facebook/react/issues/11538#issuecomment-417504600)
* except that we catch the exception rather than sanity checking every call,
* and we remove the child from whatever its parent actually is rather than
* doing nothing (the workaround in the comment leaves the element in the DOM,
* which in the case of https://github.com/vector-im/riot-web/issues/13557
* makes it fail by adding another submit button to the page every time you
* try to log in, which is also a fairly terrible failure mode).
*/
function monkeyPatchForReact() {
function findAncestorWithClass(node) {
let depth = 0;
while (node) {
if (node.className) return [node, depth];
node = node.parentNode;
++depth;
}
return [null, 0];
}
const originalRemoveChild = Node.prototype.removeChild;
Node.prototype.removeChild = function(...args) {
try {
return originalRemoveChild.apply(this, args);
} catch (e) {
const [ancestor, depth] = findAncestorWithClass(args[0]);
console.log(
"Caught exception from removeChild, removing node of type " +
args[0].nodeName + ". Closest ancestor with class is a " + ancestor.nodeName +
" with class " + ancestor.className + " " + depth + " levels above. " +
"See https://github.com/vector-im/riot-web/issues/13557", e,
);
return originalRemoveChild.apply(args[0].parentNode, args);
}
}
const originalInsertBefore = Node.prototype.insertBefore;
Node.prototype.insertBefore = function(...args) {
try {
return originalInsertBefore.apply(this, args);
} catch (e) {
const [ancestor, depth] = findAncestorWithClass(args[0]);
console.log(
"Caught exception from removeChild, removing " + args[0].nodeName +
". Closest ancestor with class is a " + ancestor.nodeName +
" with class " + ancestor.class + " " + depth + " levels above. " +
"See https://github.com/vector-im/riot-web/issues/13557", e,
);
// We could use appendChild instead, then the node would
// be in the DOM but not necessarily in the right place?
// For now, do nothing.
return args[0];
}
}
}
const supportedBrowser = checkBrowserFeatures();
// React depends on Map & Set which we check for using modernizr's es6collections
@@ -190,6 +254,8 @@ async function start() {
await loadThemePromise;
await loadLanguagePromise;
monkeyPatchForReact();
// Finally, load the app. All of the other react-sdk imports are in this file which causes the skinner to
// run on the components.
await loadApp(fragparts.params);

View File

@@ -1,3 +1,5 @@
// @flow
/*
Copyright 2016 Aviral Dasgupta
Copyright 2016 OpenMarket Ltd
@@ -18,22 +20,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import VectorBasePlatform from './VectorBasePlatform';
import {UpdateCheckStatus} from "matrix-react-sdk/src/BasePlatform";
import BaseEventIndexManager, {
CrawlerCheckpoint,
EventAndProfile,
IndexStats,
MatrixEvent,
MatrixProfile,
SearchArgs,
SearchResult
} from 'matrix-react-sdk/src/indexing/BaseEventIndexManager';
import dis from 'matrix-react-sdk/src/dispatcher/dispatcher';
import {_t, _td} from 'matrix-react-sdk/src/languageHandler';
import VectorBasePlatform, {updateCheckStatusEnum} from './VectorBasePlatform';
import BaseEventIndexManager from 'matrix-react-sdk/src/indexing/BaseEventIndexManager';
import dis from 'matrix-react-sdk/src/dispatcher';
import { _t, _td } from 'matrix-react-sdk/src/languageHandler';
import * as rageshake from 'matrix-react-sdk/src/rageshake/rageshake';
import {MatrixClient} from "matrix-js-sdk/src/client";
import {Room} from "matrix-js-sdk/src/models/room";
import {MatrixClient} from "matrix-js-sdk";
import Modal from "matrix-react-sdk/src/Modal";
import InfoDialog from "matrix-react-sdk/src/components/views/dialogs/InfoDialog";
import Spinner from "matrix-react-sdk/src/components/views/elements/Spinner";
@@ -41,10 +33,6 @@ import {Categories, Modifiers, registerShortcut} from "matrix-react-sdk/src/acce
import {Key} from "matrix-react-sdk/src/Keyboard";
import React from "react";
import {randomString} from "matrix-js-sdk/src/randomstring";
import {Action} from "matrix-react-sdk/src/dispatcher/actions";
import {ActionPayload} from "matrix-react-sdk/src/dispatcher/payloads";
import {showToast as showUpdateToast} from "matrix-react-sdk/src/toasts/UpdateToast";
import { CheckUpdatesPayload } from 'matrix-react-sdk/src/dispatcher/payloads/CheckUpdatesPayload';
const ipcRenderer = window.ipcRenderer;
const isMac = navigator.platform.toUpperCase().includes('MAC');
@@ -68,80 +56,73 @@ function platformFriendlyName(): string {
}
}
function _onAction(payload: ActionPayload) {
function _onAction(payload: Object) {
// Whitelist payload actions, no point sending most across
if (['call_state'].includes(payload.action)) {
ipcRenderer.send('app_onAction', payload);
}
}
function getUpdateCheckStatus(status: boolean | string) {
function getUpdateCheckStatus(status) {
if (status === true) {
return { status: UpdateCheckStatus.Downloading };
return { status: updateCheckStatusEnum.DOWNLOADING };
} else if (status === false) {
return { status: UpdateCheckStatus.NotAvailable };
return { status: updateCheckStatusEnum.NOTAVAILABLE };
} else {
return {
status: UpdateCheckStatus.Error,
status: updateCheckStatusEnum.ERROR,
detail: status,
};
}
}
interface IPCPayload {
id?: number;
error?: string;
reply?: any;
}
class SeshatIndexManager extends BaseEventIndexManager {
private pendingIpcCalls: Record<number, { resolve, reject }> = {};
private nextIpcCallId: number = 0;
constructor() {
super();
ipcRenderer.on('seshatReply', this._onIpcReply);
this._pendingIpcCalls = {};
this._nextIpcCallId = 0;
ipcRenderer.on('seshatReply', this._onIpcReply.bind(this));
}
async _ipcCall(name: string, ...args: any[]): Promise<any> {
async _ipcCall(name: string, ...args: []): Promise<{}> {
// TODO this should be moved into the preload.js file.
const ipcCallId = ++this.nextIpcCallId;
const ipcCallId = ++this._nextIpcCallId;
return new Promise((resolve, reject) => {
this.pendingIpcCalls[ipcCallId] = {resolve, reject};
this._pendingIpcCalls[ipcCallId] = {resolve, reject};
window.ipcRenderer.send('seshat', {id: ipcCallId, name, args});
});
}
_onIpcReply = (ev: {}, payload: IPCPayload) => {
_onIpcReply(ev: {}, payload: {}) {
if (payload.id === undefined) {
console.warn("Ignoring IPC reply with no ID");
return;
}
if (this.pendingIpcCalls[payload.id] === undefined) {
if (this._pendingIpcCalls[payload.id] === undefined) {
console.warn("Unknown IPC payload ID: " + payload.id);
return;
}
const callbacks = this.pendingIpcCalls[payload.id];
delete this.pendingIpcCalls[payload.id];
const callbacks = this._pendingIpcCalls[payload.id];
delete this._pendingIpcCalls[payload.id];
if (payload.error) {
callbacks.reject(payload.error);
} else {
callbacks.resolve(payload.reply);
}
};
}
async supportsEventIndexing(): Promise<boolean> {
return this._ipcCall('supportsEventIndexing');
}
async initEventIndex(): Promise<void> {
async initEventIndex(): Promise<> {
return this._ipcCall('initEventIndex');
}
async addEventToIndex(ev: MatrixEvent, profile: MatrixProfile): Promise<void> {
async addEventToIndex(ev: MatrixEvent, profile: MatrixProfile): Promise<> {
return this._ipcCall('addEventToIndex', ev, profile);
}
@@ -153,27 +134,27 @@ class SeshatIndexManager extends BaseEventIndexManager {
return this._ipcCall('isEventIndexEmpty');
}
async commitLiveEvents(): Promise<void> {
async commitLiveEvents(): Promise<> {
return this._ipcCall('commitLiveEvents');
}
async searchEventIndex(searchConfig: SearchArgs): Promise<SearchResult> {
async searchEventIndex(searchConfig: SearchConfig): Promise<SearchResult> {
return this._ipcCall('searchEventIndex', searchConfig);
}
async addHistoricEvents(
events: [EventAndProfile],
events: [HistoricEvent],
checkpoint: CrawlerCheckpoint | null,
oldCheckpoint: CrawlerCheckpoint | null,
): Promise<boolean> {
): Promise<> {
return this._ipcCall('addHistoricEvents', events, checkpoint, oldCheckpoint);
}
async addCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise<void> {
async addCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise<> {
return this._ipcCall('addCrawlerCheckpoint', checkpoint);
}
async removeCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise<void> {
async removeCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise<> {
return this._ipcCall('removeCrawlerCheckpoint', checkpoint);
}
@@ -185,29 +166,27 @@ class SeshatIndexManager extends BaseEventIndexManager {
return this._ipcCall('loadCheckpoints');
}
async closeEventIndex(): Promise<void> {
async closeEventIndex(): Promise<> {
return this._ipcCall('closeEventIndex');
}
async getStats(): Promise<IndexStats> {
async getStats(): Promise<> {
return this._ipcCall('getStats');
}
async deleteEventIndex(): Promise<void> {
async deleteEventIndex(): Promise<> {
return this._ipcCall('deleteEventIndex');
}
}
export default class ElectronPlatform extends VectorBasePlatform {
private eventIndexManager: BaseEventIndexManager = new SeshatIndexManager();
private pendingIpcCalls: Record<number, { resolve, reject }> = {};
private nextIpcCallId: number = 0;
// this is the opaque token we pass to the HS which when we get it in our callback we can resolve to a profile
private ssoID: string = randomString(32);
constructor() {
super();
this._pendingIpcCalls = {};
this._nextIpcCallId = 0;
this.eventIndexManager = new SeshatIndexManager();
dis.register(_onAction);
/*
IPC Call `check_updates` returns:
@@ -216,10 +195,12 @@ export default class ElectronPlatform extends VectorBasePlatform {
or the error if one is encountered
*/
ipcRenderer.on('check_updates', (event, status) => {
dis.dispatch<CheckUpdatesPayload>({
action: Action.CheckUpdates,
...getUpdateCheckStatus(status),
if (!this.showUpdateCheck) return;
dis.dispatch({
action: 'check_updates',
value: getUpdateCheckStatus(status),
});
this.showUpdateCheck = false;
});
// try to flush the rageshake logs to indexeddb before quit.
@@ -232,9 +213,12 @@ export default class ElectronPlatform extends VectorBasePlatform {
ipcRenderer.on('update-downloaded', this.onUpdateDownloaded.bind(this));
ipcRenderer.on('preferences', () => {
dis.fire(Action.ViewUserSettings);
dis.dispatch({ action: 'view_user_settings' });
});
this.startUpdateCheck = this.startUpdateCheck.bind(this);
this.stopUpdateCheck = this.stopUpdateCheck.bind(this);
// register OS-specific shortcuts
if (isMac) {
registerShortcut(Categories.NAVIGATION, {
@@ -268,6 +252,8 @@ export default class ElectronPlatform extends VectorBasePlatform {
});
}
// this is the opaque token we pass to the HS which when we get it in our callback we can resolve to a profile
this.ssoID = randomString(32);
this._ipcCall("startSSOFlow", this.ssoID);
}
@@ -275,10 +261,13 @@ export default class ElectronPlatform extends VectorBasePlatform {
return this._ipcCall('getConfig');
}
async onUpdateDownloaded(ev, {releaseNotes, releaseName}) {
if (this.shouldShowUpdate(releaseName)) {
showUpdateToast(await this.getAppVersion(), releaseName, releaseNotes);
}
async onUpdateDownloaded(ev, updateInfo) {
dis.dispatch({
action: 'new_version',
currentVersion: await this.getAppVersion(),
newVersion: updateInfo,
releaseNotes: updateInfo.releaseNotes,
});
}
getHumanReadableName(): string {
@@ -300,7 +289,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
return true;
}
displayNotification(title: string, msg: string, avatarUrl: string, room: Room): Notification {
displayNotification(title: string, msg: string, avatarUrl: string, room: Object): Notification {
// GNOME notification spec parses HTML tags for styling...
// Electron Docs state all supported linux notification systems follow this markup spec
// https://github.com/electron/electron/blob/master/docs/tutorial/desktop-environment-integration.md#linux
@@ -317,14 +306,14 @@ export default class ElectronPlatform extends VectorBasePlatform {
silent: true, // we play our own sounds
};
if (avatarUrl) notifBody['icon'] = avatarUrl;
const notification = new window.Notification(title, notifBody);
const notification = new global.Notification(title, notifBody);
notification.onclick = () => {
dis.dispatch({
action: 'view_room',
room_id: room.roomId,
});
window.focus();
global.focus();
this._ipcCall('focusWindow');
};
@@ -347,11 +336,11 @@ export default class ElectronPlatform extends VectorBasePlatform {
return true;
}
async getAutoLaunchEnabled(): Promise<boolean> {
async getAutoLaunchEnabled(): boolean {
return this._ipcCall('getAutoLaunchEnabled');
}
async setAutoLaunchEnabled(enabled: boolean): Promise<void> {
async setAutoLaunchEnabled(enabled: boolean): void {
return this._ipcCall('setAutoLaunchEnabled', enabled);
}
@@ -360,11 +349,11 @@ export default class ElectronPlatform extends VectorBasePlatform {
return !isMac;
}
async getAutoHideMenuBarEnabled(): Promise<boolean> {
async getAutoHideMenuBarEnabled(): boolean {
return this._ipcCall('getAutoHideMenuBarEnabled');
}
async setAutoHideMenuBarEnabled(enabled: boolean): Promise<void> {
async setAutoHideMenuBarEnabled(enabled: boolean): void {
return this._ipcCall('setAutoHideMenuBarEnabled', enabled);
}
@@ -373,21 +362,23 @@ export default class ElectronPlatform extends VectorBasePlatform {
return !isMac;
}
async getMinimizeToTrayEnabled(): Promise<boolean> {
async getMinimizeToTrayEnabled(): boolean {
return this._ipcCall('getMinimizeToTrayEnabled');
}
async setMinimizeToTrayEnabled(enabled: boolean): Promise<void> {
async setMinimizeToTrayEnabled(enabled: boolean): void {
return this._ipcCall('setMinimizeToTrayEnabled', enabled);
}
async canSelfUpdate(): Promise<boolean> {
async canSelfUpdate(): boolean {
const feedUrl = await this._ipcCall('getUpdateFeedUrl');
return Boolean(feedUrl);
}
startUpdateCheck() {
if (this.showUpdateCheck) return;
super.startUpdateCheck();
ipcRenderer.send('check_updates');
}
@@ -402,7 +393,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
return _t('Riot Desktop (%(platformName)s)', { platformName: platformFriendlyName() });
}
screenCaptureErrorString(): string | null {
screenCaptureErrorString(): ?string {
return null;
}
@@ -417,10 +408,10 @@ export default class ElectronPlatform extends VectorBasePlatform {
window.location.reload(false);
}
async _ipcCall(name: string, ...args: any[]): Promise<any> {
const ipcCallId = ++this.nextIpcCallId;
async _ipcCall(name, ...args) {
const ipcCallId = ++this._nextIpcCallId;
return new Promise((resolve, reject) => {
this.pendingIpcCalls[ipcCallId] = {resolve, reject};
this._pendingIpcCalls[ipcCallId] = {resolve, reject};
window.ipcRenderer.send('ipcCall', {id: ipcCallId, name, args});
// Maybe add a timeout to these? Probably not necessary.
});
@@ -432,13 +423,13 @@ export default class ElectronPlatform extends VectorBasePlatform {
return;
}
if (this.pendingIpcCalls[payload.id] === undefined) {
if (this._pendingIpcCalls[payload.id] === undefined) {
console.warn("Unknown IPC payload ID: " + payload.id);
return;
}
const callbacks = this.pendingIpcCalls[payload.id];
delete this.pendingIpcCalls[payload.id];
const callbacks = this._pendingIpcCalls[payload.id];
delete this._pendingIpcCalls[payload.id];
if (payload.error) {
callbacks.reject(payload.error);
} else {
@@ -457,16 +448,15 @@ export default class ElectronPlatform extends VectorBasePlatform {
});
}
getSSOCallbackUrl(fragmentAfterLogin: string): URL {
const url = super.getSSOCallbackUrl(fragmentAfterLogin);
getSSOCallbackUrl(hsUrl: string, isUrl: string): URL {
const url = super.getSSOCallbackUrl(hsUrl, isUrl);
url.protocol = "riot";
url.searchParams.set("riot-desktop-ssoid", this.ssoID);
return url;
}
startSingleSignOn(mxClient: MatrixClient, loginType: "sso" | "cas", fragmentAfterLogin: string) {
// this will get intercepted by electron-main will-navigate
super.startSingleSignOn(mxClient, loginType, fragmentAfterLogin);
startSingleSignOn(mxClient: MatrixClient, loginType: "sso" | "cas") {
super.startSingleSignOn(mxClient, loginType); // this will get intercepted by electron-main will-navigate
Modal.createTrackedDialog('Electron', 'SSO', InfoDialog, {
title: _t("Go to your browser to complete Sign In"),
description: <Spinner />,

View File

@@ -0,0 +1,176 @@
// @flow
/*
Copyright 2016 Aviral Dasgupta
Copyright 2016 OpenMarket Ltd
Copyright 2018 New Vector Ltd
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import BasePlatform from 'matrix-react-sdk/src/BasePlatform';
import { _t } from 'matrix-react-sdk/src/languageHandler';
import dis from 'matrix-react-sdk/src/dispatcher';
import {getVectorConfig} from "../getconfig";
import Favico from 'favico.js';
export const updateCheckStatusEnum = {
CHECKING: 'CHECKING',
ERROR: 'ERROR',
NOTAVAILABLE: 'NOTAVAILABLE',
DOWNLOADING: 'DOWNLOADING',
READY: 'READY',
};
/**
* Vector-specific extensions to the BasePlatform template
*/
export default class VectorBasePlatform extends BasePlatform {
constructor() {
super();
this.showUpdateCheck = false;
this.startUpdateCheck = this.startUpdateCheck.bind(this);
this.stopUpdateCheck = this.stopUpdateCheck.bind(this);
}
async getConfig(): Promise<{}> {
return getVectorConfig();
}
getHumanReadableName(): string {
return 'Vector Base Platform'; // no translation required: only used for analytics
}
/**
* Delay creating the `Favico` instance until first use (on the first notification) as
* it uses canvas, which can trigger a permission prompt in Firefox's resist
* fingerprinting mode.
* See https://github.com/vector-im/riot-web/issues/9605.
*/
get favicon() {
if (this._favicon) {
return this._favicon;
}
// The 'animations' are really low framerate and look terrible.
// Also it re-starts the animation every time you set the badge,
// and we set the state each time, even if the value hasn't changed,
// so we'd need to fix that if enabling the animation.
this._favicon = new Favico({ animation: 'none' });
return this._favicon;
}
_updateFavicon() {
try {
// This needs to be in in a try block as it will throw
// if there are more than 100 badge count changes in
// its internal queue
let bgColor = "#d00";
let notif = this.notificationCount;
if (this.errorDidOccur) {
notif = notif || "×";
bgColor = "#f00";
}
const doUpdate = () => {
this.favicon.badge(notif, {
bgColor: bgColor,
});
};
doUpdate();
// HACK: Workaround for Chrome 78+ and dependency incompatibility.
// The library we use doesn't appear to work in Chrome 78, likely due to their
// changes surrounding tab behaviour. Tabs went through a bit of a redesign and
// restructuring in Chrome 78, so it's not terribly surprising that the library
// doesn't work correctly. The library we use hasn't been updated in years and
// does not look easy to fix/fork ourselves - we might as well write our own that
// doesn't include animation/webcam/etc support. However, that's a bit difficult
// so for now we'll just trigger the update twice.
//
// Note that trying to reproduce the problem in isolation doesn't seem to work:
// see https://gist.github.com/turt2live/5ab87919918adbfd7cfb8f1ad10f2409 for
// an example (you'll need your own web server to host that).
if (window.chrome) {
doUpdate();
}
} catch (e) {
console.warn(`Failed to set badge count: ${e.message}`);
}
}
setNotificationCount(count: number) {
if (this.notificationCount === count) return;
super.setNotificationCount(count);
this._updateFavicon();
}
setErrorStatus(errorDidOccur: boolean) {
if (this.errorDidOccur === errorDidOccur) return;
super.setErrorStatus(errorDidOccur);
this._updateFavicon();
}
/**
* Begin update polling, if applicable
*/
startUpdater() {
}
/**
* Whether we can call checkForUpdate on this platform build
*/
async canSelfUpdate(): boolean {
return false;
}
startUpdateCheck() {
this.showUpdateCheck = true;
dis.dispatch({
action: 'check_updates',
value: { status: updateCheckStatusEnum.CHECKING },
});
}
stopUpdateCheck() {
this.showUpdateCheck = false;
dis.dispatch({
action: 'check_updates',
value: false,
});
}
getUpdateCheckStatusEnum() {
return updateCheckStatusEnum;
}
/**
* Update the currently running app to the latest available
* version and replace this instance of the app with the
* new version.
*/
installUpdate() {
}
/**
* Get a sensible default display name for the
* device Vector is running on
*/
getDefaultDeviceDisplayName(): string {
return _t("Unknown device");
}
}

View File

@@ -1,97 +0,0 @@
/*
Copyright 2016 Aviral Dasgupta
Copyright 2016 OpenMarket Ltd
Copyright 2018, 2020 New Vector Ltd
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import BasePlatform from 'matrix-react-sdk/src/BasePlatform';
import {_t} from 'matrix-react-sdk/src/languageHandler';
import {getVectorConfig} from "../getconfig";
import Favicon from "../../favicon";
export const updateCheckStatusEnum = {
CHECKING: 'CHECKING',
ERROR: 'ERROR',
NOTAVAILABLE: 'NOTAVAILABLE',
DOWNLOADING: 'DOWNLOADING',
READY: 'READY',
};
/**
* Vector-specific extensions to the BasePlatform template
*/
export default abstract class VectorBasePlatform extends BasePlatform {
protected _favicon: Favicon;
async getConfig(): Promise<{}> {
return getVectorConfig();
}
getHumanReadableName(): string {
return 'Vector Base Platform'; // no translation required: only used for analytics
}
/**
* Delay creating the `Favicon` instance until first use (on the first notification) as
* it uses canvas, which can trigger a permission prompt in Firefox's resist fingerprinting mode.
* See https://github.com/vector-im/riot-web/issues/9605.
*/
get favicon() {
if (this._favicon) {
return this._favicon;
}
return this._favicon = new Favicon();
}
_updateFavicon() {
let bgColor = "#d00";
let notif: string | number = this.notificationCount;
if (this.errorDidOccur) {
notif = notif || "×";
bgColor = "#f00";
}
this.favicon.badge(notif, { bgColor });
}
setNotificationCount(count: number) {
if (this.notificationCount === count) return;
super.setNotificationCount(count);
this._updateFavicon();
}
setErrorStatus(errorDidOccur: boolean) {
if (this.errorDidOccur === errorDidOccur) return;
super.setErrorStatus(errorDidOccur);
this._updateFavicon();
}
/**
* Begin update polling, if applicable
*/
startUpdater() {
}
/**
* Get a sensible default display name for the
* device Vector is running on
*/
getDefaultDeviceDisplayName(): string {
return _t("Unknown device");
}
}

View File

@@ -1,3 +1,5 @@
// @flow
/*
Copyright 2016 Aviral Dasgupta
Copyright 2016 OpenMarket Ltd
@@ -16,15 +18,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import VectorBasePlatform from './VectorBasePlatform';
import {UpdateCheckStatus} from "matrix-react-sdk/src/BasePlatform";
import VectorBasePlatform, {updateCheckStatusEnum} from './VectorBasePlatform';
import request from 'browser-request';
import dis from 'matrix-react-sdk/src/dispatcher/dispatcher';
import {_t} from 'matrix-react-sdk/src/languageHandler';
import {Room} from "matrix-js-sdk/src/models/room";
import {hideToast as hideUpdateToast, showToast as showUpdateToast} from "matrix-react-sdk/src/toasts/UpdateToast";
import {Action} from "matrix-react-sdk/src/dispatcher/actions";
import { CheckUpdatesPayload } from 'matrix-react-sdk/src/dispatcher/payloads/CheckUpdatesPayload';
import dis from 'matrix-react-sdk/src/dispatcher';
import { _t } from 'matrix-react-sdk/src/languageHandler';
import url from 'url';
import UAParser from 'ua-parser-js';
@@ -32,7 +29,13 @@ import UAParser from 'ua-parser-js';
const POKE_RATE_MS = 10 * 60 * 1000; // 10 min
export default class WebPlatform extends VectorBasePlatform {
private runningVersion: string = null;
constructor() {
super();
this.runningVersion = null;
this.startUpdateCheck = this.startUpdateCheck.bind(this);
this.stopUpdateCheck = this.stopUpdateCheck.bind(this);
}
getHumanReadableName(): string {
return 'Web Platform'; // no translation required: only used for analytics
@@ -43,7 +46,7 @@ export default class WebPlatform extends VectorBasePlatform {
* notifications, otherwise false.
*/
supportsNotifications(): boolean {
return Boolean(window.Notification);
return Boolean(global.Notification);
}
/**
@@ -51,7 +54,7 @@ export default class WebPlatform extends VectorBasePlatform {
* to display notifications. Otherwise false.
*/
maySendNotifications(): boolean {
return window.Notification.permission === 'granted';
return global.Notification.permission === 'granted';
}
/**
@@ -66,27 +69,27 @@ export default class WebPlatform extends VectorBasePlatform {
// promise, but this is only supported in Chrome 46
// and Firefox 47, so adapt the callback API.
return new Promise(function(resolve, reject) {
window.Notification.requestPermission((result) => {
global.Notification.requestPermission((result) => {
resolve(result);
});
});
}
displayNotification(title: string, msg: string, avatarUrl: string, room: Room) {
displayNotification(title: string, msg: string, avatarUrl: string, room: Object) {
const notifBody = {
body: msg,
tag: "vector",
silent: true, // we play our own sounds
};
if (avatarUrl) notifBody['icon'] = avatarUrl;
const notification = new window.Notification(title, notifBody);
const notification = new global.Notification(title, notifBody);
notification.onclick = function() {
dis.dispatch({
action: 'view_room',
room_id: room.roomId,
});
window.focus();
global.focus();
notification.close();
};
}
@@ -128,42 +131,45 @@ export default class WebPlatform extends VectorBasePlatform {
startUpdater() {
this.pollForUpdate();
setInterval(this.pollForUpdate, POKE_RATE_MS);
setInterval(this.pollForUpdate.bind(this), POKE_RATE_MS);
}
async canSelfUpdate(): Promise<boolean> {
async canSelfUpdate(): boolean {
return true;
}
pollForUpdate = () => {
pollForUpdate() {
return this._getVersion().then((ver) => {
if (this.runningVersion === null) {
this.runningVersion = ver;
} else if (this.runningVersion !== ver) {
if (this.shouldShowUpdate(ver)) {
showUpdateToast(this.runningVersion, ver);
}
return { status: UpdateCheckStatus.Ready };
} else {
hideUpdateToast();
dis.dispatch({
action: 'new_version',
currentVersion: this.runningVersion,
newVersion: ver,
});
// Return to skip a MatrixChat state update
return;
}
return { status: UpdateCheckStatus.NotAvailable };
return { status: updateCheckStatusEnum.NOTAVAILABLE };
}, (err) => {
console.error("Failed to poll for update", err);
return {
status: UpdateCheckStatus.Error,
status: updateCheckStatusEnum.ERROR,
detail: err.message || err.status ? err.status.toString() : 'Unknown Error',
};
});
};
}
startUpdateCheck() {
if (this.showUpdateCheck) return;
super.startUpdateCheck();
this.pollForUpdate().then((updateState) => {
dis.dispatch<CheckUpdatesPayload>({
action: Action.CheckUpdates,
...updateState,
if (!this.showUpdateCheck) return;
if (!updateState) return;
dis.dispatch({
action: 'check_updates',
value: updateState,
});
});
}
@@ -198,9 +204,9 @@ export default class WebPlatform extends VectorBasePlatform {
});
}
screenCaptureErrorString(): string | null {
screenCaptureErrorString(): ?string {
// it won't work at all if you're not on HTTPS so whine whine whine
if (window.location.protocol !== "https:") {
if (!global.window || global.window.location.protocol !== "https:") {
return _t("You need to be using HTTPS to place a screen-sharing call.");
}
return null;

View File

@@ -29,7 +29,7 @@ import * as jssdk from 'matrix-js-sdk';
import * as sdk from 'matrix-react-sdk';
import {MatrixClientPeg} from 'matrix-react-sdk/src/MatrixClientPeg';
import {Views} from 'matrix-react-sdk/src/components/structures/MatrixChat';
import dis from 'matrix-react-sdk/src/dispatcher/dispatcher';
import dis from 'matrix-react-sdk/src/dispatcher';
import * as test_utils from '../test-utils';
import MockHttpBackend from 'matrix-mock-request';
import {parseQs, parseQsFromFragment} from '../../src/vector/url_utils';
@@ -589,10 +589,8 @@ describe('loading:', function() {
describe('Token login:', function() {
it('logs in successfully', function() {
localStorage.setItem("mx_hs_url", "https://homeserver");
localStorage.setItem("mx_is_url", "https://idserver");
loadApp({
queryString: "?loginToken=secretToken",
queryString: "?loginToken=secretToken&homeserver=https%3A%2F%2Fhomeserver&identityServer=https%3A%2F%2Fidserver",
});
return sleep(1).then(() => {

View File

@@ -14,8 +14,7 @@
"jsx": "react",
"types": [
"node",
"react",
"flux"
"react"
]
},
"include": [

View File

@@ -216,10 +216,10 @@ module.exports = (env, argv) => {
// Note that we use slightly different plugins for SCSS.
require('postcss-import')(),
require("postcss-mixins")(),
require("postcss-simple-vars")(),
require("postcss-extend")(),
require("postcss-nested")(),
require("postcss-mixins")(),
require("postcss-easings")(),
require("postcss-strip-inline-comments")(),
require("postcss-hexrgba")(),

1079
yarn.lock

File diff suppressed because it is too large Load Diff