aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar alx2019-03-16 23:56:27 +0300
committerGravatar alx2019-03-16 23:56:27 +0300
commit06105f76dbfa3b65e63ed06f9c4d5107bd49ed88 (patch)
tree5702c01cec9688039d891f4a711878706101c1c5
parent3ea4cd1942fa4e763034da11c5fa429407b67829 (diff)
parenta49105285d0d7719d7f222a507af2d5ac5b4bdb1 (diff)
Merge remote-tracking branch 'origin/master'
-rw-r--r--.gitmodules3
-rw-r--r--.stylelintrc.json1
-rw-r--r--build.gradle51
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin55746 -> 55190 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties2
m---------java-telegram-bot-api0
-rw-r--r--package.json33
-rw-r--r--src/main/assets/embed.js4
-rw-r--r--src/main/assets/scripts.js2
-rw-r--r--src/main/java/com/juick/Message.java40
-rw-r--r--src/main/java/com/juick/User.java36
-rw-r--r--src/main/java/com/juick/formatters/PlainTextFormatter.java10
-rw-r--r--src/main/java/com/juick/model/UserInfo.java60
-rw-r--r--src/main/java/com/juick/model/facebook/User.java70
-rw-r--r--src/main/java/com/juick/model/twitter/User.java4
-rw-r--r--src/main/java/com/juick/model/vk/Token.java14
-rw-r--r--src/main/java/com/juick/model/vk/User.java18
-rw-r--r--src/main/java/com/juick/model/vk/UsersResponse.java4
-rw-r--r--src/main/java/com/juick/server/ActivityPubManager.java7
-rw-r--r--src/main/java/com/juick/server/CommandsManager.java34
-rw-r--r--src/main/java/com/juick/server/KeystoreManager.java9
-rw-r--r--src/main/java/com/juick/server/ServerManager.java120
-rw-r--r--src/main/java/com/juick/server/SignatureManager.java92
-rw-r--r--src/main/java/com/juick/server/WebsocketManager.java174
-rw-r--r--src/main/java/com/juick/server/XMPPManager.java (renamed from src/main/java/com/juick/server/XMPPConnection.java)92
-rw-r--r--src/main/java/com/juick/server/XMPPServer.java429
-rw-r--r--src/main/java/com/juick/server/api/ApiSocialLogin.java70
-rw-r--r--src/main/java/com/juick/server/api/Index.java14
-rw-r--r--src/main/java/com/juick/server/api/Messages.java3
-rw-r--r--src/main/java/com/juick/server/api/Notifications.java21
-rw-r--r--src/main/java/com/juick/server/api/PM.java1
-rw-r--r--src/main/java/com/juick/server/api/Users.java59
-rw-r--r--src/main/java/com/juick/server/api/activity/Profile.java117
-rw-r--r--src/main/java/com/juick/server/api/activity/helpers/ActivityIdDeserializer.java22
-rw-r--r--src/main/java/com/juick/server/api/activity/helpers/LinkValueDeserializer.java21
-rw-r--r--src/main/java/com/juick/server/api/activity/model/Activity.java4
-rw-r--r--src/main/java/com/juick/server/api/activity/model/Context.java3
-rw-r--r--src/main/java/com/juick/server/api/rss/MessagesView.java2
-rw-r--r--src/main/java/com/juick/server/api/webfinger/Resource.java2
-rw-r--r--src/main/java/com/juick/server/api/xnodeinfo2/Info.java40
-rw-r--r--src/main/java/com/juick/server/api/xnodeinfo2/model/NodeInfo.java35
-rw-r--r--src/main/java/com/juick/server/api/xnodeinfo2/model/Server.java6
-rw-r--r--src/main/java/com/juick/server/api/xnodeinfo2/model/ServiceInfo.java3
-rw-r--r--src/main/java/com/juick/server/api/xnodeinfo2/model/Usage.java3
-rw-r--r--src/main/java/com/juick/server/api/xnodeinfo2/model/UserStats.java3
-rw-r--r--src/main/java/com/juick/server/configuration/ActivityPubClientConfig.java8
-rw-r--r--src/main/java/com/juick/server/configuration/ApiAppConfiguration.java29
-rw-r--r--src/main/java/com/juick/server/configuration/BaseWebConfiguration.java18
-rw-r--r--src/main/java/com/juick/server/configuration/SecurityConfig.java40
-rw-r--r--src/main/java/com/juick/server/configuration/XMPPConfig.java34
-rw-r--r--src/main/java/com/juick/server/helpers/HeaderRequestInterceptor.java26
-rw-r--r--src/main/java/com/juick/server/util/ImageUtils.java2
-rw-r--r--src/main/java/com/juick/server/www/VaryHandler.java14
-rw-r--r--src/main/java/com/juick/server/www/controllers/AnythingFilter.java2
-rw-r--r--src/main/java/com/juick/server/www/controllers/MessagesWWW.java42
-rw-r--r--src/main/java/com/juick/server/www/controllers/Settings.java14
-rw-r--r--src/main/java/com/juick/server/www/controllers/SocialLogin.java70
-rw-r--r--src/main/java/com/juick/server/xmpp/XMPPStatusPage.java32
-rw-r--r--src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java48
-rw-r--r--src/main/java/com/juick/server/xmpp/router/Handshake.java39
-rw-r--r--src/main/java/com/juick/server/xmpp/router/Stream.java202
-rw-r--r--src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java57
-rw-r--r--src/main/java/com/juick/server/xmpp/router/StreamError.java57
-rw-r--r--src/main/java/com/juick/server/xmpp/router/StreamFeatures.java95
-rw-r--r--src/main/java/com/juick/server/xmpp/router/StreamHandler.java13
-rw-r--r--src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java10
-rw-r--r--src/main/java/com/juick/server/xmpp/router/XMPPError.java73
-rw-r--r--src/main/java/com/juick/server/xmpp/router/XMPPRouter.java220
-rw-r--r--src/main/java/com/juick/server/xmpp/router/XmlUtils.java88
-rw-r--r--src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java68
-rw-r--r--src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java40
-rw-r--r--src/main/java/com/juick/server/xmpp/s2s/Connection.java158
-rw-r--r--src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java231
-rw-r--r--src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java16
-rw-r--r--src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java189
-rw-r--r--src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java65
-rw-r--r--src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java28
-rw-r--r--src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java37
-rw-r--r--src/main/java/com/juick/service/CrosspostService.java4
-rw-r--r--src/main/java/com/juick/service/CrosspostServiceImpl.java12
-rw-r--r--src/main/java/com/juick/service/MessagesService.java6
-rw-r--r--src/main/java/com/juick/service/MessagesServiceImpl.java143
-rw-r--r--src/main/java/com/juick/service/PMQueriesServiceImpl.java6
-rw-r--r--src/main/java/com/juick/service/TagServiceImpl.java30
-rw-r--r--src/main/java/com/juick/service/UserService.java5
-rw-r--r--src/main/java/com/juick/service/UserServiceImpl.java55
-rw-r--r--src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java71
-rw-r--r--src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java7
-rw-r--r--src/main/java/com/juick/util/MessageUtils.java78
-rw-r--r--src/main/java/com/juick/util/StreamUtils.java38
-rw-r--r--src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java5
-rw-r--r--src/main/java/ru/sape/Sape.java4
-rw-r--r--src/main/java/ru/sape/SapePageLinks.java15
-rw-r--r--src/main/resources/banner.txt13
-rw-r--r--src/main/resources/db/migration/V1.17__drop tags column.sql1
-rw-r--r--src/main/resources/db/migration/V1.18__increase messages and replies timestamp precision.sql5
-rw-r--r--src/main/resources/schema.sql2
-rw-r--r--src/main/resources/templates/layouts/note.html2
-rw-r--r--src/main/resources/templates/views/login.html2
-rw-r--r--src/main/resources/templates/views/partial/footer.html2
-rw-r--r--src/main/resources/templates/views/partial/message.html6
-rw-r--r--src/main/resources/templates/views/pm_inbox.html2
-rw-r--r--src/main/resources/templates/views/pm_sent.html2
-rw-r--r--src/main/resources/templates/views/thread.html18
-rw-r--r--src/test/java/com/juick/MessageTest.java36
-rw-r--r--src/test/java/com/juick/server/configuration/TestActivityConfiguration.java19
-rw-r--r--src/test/java/com/juick/server/tests/ServerTests.java439
-rw-r--r--src/test/java/com/juick/test/util/MockUtils.java2
-rw-r--r--src/test/resources/2936611-57.jpgbin0 -> 101818 bytes
-rw-r--r--src/test/resources/announce.json1
-rw-r--r--src/test/resources/data.sql1
-rw-r--r--src/test/resources/delete_user.json1
-rw-r--r--src/test/resources/hubzilla_activity.json185
-rw-r--r--src/test/resources/hubzilla_follow.json1
-rw-r--r--src/test/resources/mocks/activity/testfollow.json15
-rw-r--r--src/test/resources/mocks/activity/testuser.json27
-rw-r--r--src/test/resources/test.p12bin0 -> 2386 bytes
-rw-r--r--webpack.config.js4
-rw-r--r--yarn.lock1943
119 files changed, 2707 insertions, 4304 deletions
diff --git a/.gitmodules b/.gitmodules
index 7e916a8b..1933cb69 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
[submodule "juick-server/src/main/resources/help"]
path = src/main/resources/help
url = git@github.com:juick/help.git
-[submodule "java-telegram-bot-api"]
- path = java-telegram-bot-api
- url = git@x.juick.com:/srv/git/java-telegram-bot-api.git
diff --git a/.stylelintrc.json b/.stylelintrc.json
index e1c32ef0..647b170f 100644
--- a/.stylelintrc.json
+++ b/.stylelintrc.json
@@ -1,6 +1,7 @@
{
"extends": "stylelint-config-standard",
"_rules_documentation" : "https://github.com/stylelint/stylelint/blob/master/docs/user-guide/rules.md",
+ "ignoreFiles": "node_modules/**",
"rules": {
"at-rule-empty-line-before": null,
"color-hex-case": null,
diff --git a/build.gradle b/build.gradle
index 84e19e3a..acaaf0f2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,14 +4,14 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0'
+ classpath 'com.github.ben-manes:gradle-versions-plugin:0.21.0'
classpath 'io.github.swagger2markup:swagger2markup-gradle-plugin:1.3.3'
}
}
plugins {
- id 'org.springframework.boot' version '2.1.1.RELEASE' apply false
+ id 'org.springframework.boot' version '2.1.3.RELEASE' apply false
id "com.moowork.node" version "1.2.0" apply false
- id("org.asciidoctor.convert") version "1.5.9.2" apply false
+ id("org.asciidoctor.convert") version "1.6.0" apply false
}
repositories {
@@ -19,7 +19,6 @@ repositories {
jcenter()
maven { url "https://jitpack.io" }
maven { url "https://repository.apache.org/content/repositories/snapshots/" }
- maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
}
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
@@ -112,15 +111,20 @@ dependencies {
compile ('org.springframework.boot:spring-boot-starter-jdbc')
compile ("org.springframework.boot:spring-boot-starter-security")
compile ("org.springframework.boot:spring-boot-starter-web")
- compile ("org.springframework.boot:spring-boot-starter-undertow")
- compile ("org.springframework.boot:spring-boot-starter-websocket")
+ compile ("org.springframework.boot:spring-boot-starter-undertow") {
+ exclude group: 'org.jboss.xnio'
+ }
+ compile ("org.jboss.xnio:xnio-nio:3.7.0.Final") {
+ exclude group: 'org.jboss.threads'
+ }
+ compile 'org.jboss.threads:jboss-threads:2.3.3.Final'
compile ("org.springframework.boot:spring-boot-starter-json")
compile ('org.springframework.boot:spring-boot-devtools')
compile "org.apache.commons:commons-lang3:3.8.1"
- compile "org.apache.commons:commons-collections4:4.2"
+ compile "org.apache.commons:commons-collections4:4.3"
compile 'org.apache.commons:commons-text:1.6'
- compile "commons-codec:commons-codec:1.11"
+ compile "commons-codec:commons-codec:1.12"
compile "commons-io:commons-io:2.6"
compile 'com.google.code.findbugs:jsr305:3.0.2'
@@ -128,25 +132,23 @@ dependencies {
compile 'org.imgscalr:imgscalr-lib:4.2'
compile "org.apache.commons:commons-imaging:1.0-SNAPSHOT"
runtime "commons-fileupload:commons-fileupload:1.3.3"
- compile 'com.github.ben-manes.caffeine:caffeine:2.6.2'
+ compile 'com.github.ben-manes.caffeine:caffeine:2.7.0'
compile "javax.inject:javax.inject:1"
compile "javax.xml.bind:jaxb-api:2.3.1"
- compile 'org.glassfish.jaxb:jaxb-runtime:2.3.1'
+ runtime 'org.glassfish.jaxb:jaxb-runtime:2.3.2'
compileOnly 'io.springfox:springfox-core:2.9.2'
compile 'org.apache.commons:commons-email:1.5'
- compile 'com.github.scribejava:scribejava-apis:6.1.0'
- compile 'com.github.vitalyster:java-telegram-bot-api:file_api-SNAPSHOT'
+ compile 'com.github.scribejava:scribejava-apis:6.3.0'
+ compile 'com.github.pengrad:java-telegram-bot-api:4.1.1'
compile 'com.twelvemonkeys.imageio:imageio-jpeg:3.4.1'
compile 'org.imgscalr:imgscalr-lib:4.2'
compile 'org.twitter4j:twitter4j-core:4.0.7'
- compile 'xpp3:xpp3:1.1.4c'
-
- compile 'rocks.xmpp:xmpp-core-client:0.8.1-SNAPSHOT'
- compile 'rocks.xmpp:xmpp-extensions-client:0.8.1-SNAPSHOT'
+ compile 'rocks.xmpp:xmpp-core-client:0.8.1'
+ compile 'rocks.xmpp:xmpp-extensions-client:0.8.1'
compile "javax.inject:javax.inject:1"
@@ -156,19 +158,21 @@ dependencies {
compile 'org.flywaydb:flyway-core:5.2.4'
runtime 'org.mariadb.jdbc:mariadb-java-client:2.3.0'
- runtime 'com.h2database:h2:1.4.196'
- runtime "commons-fileupload:commons-fileupload:1.3.3"
+ runtime 'net.java.dev.jna:jna:5.2.0'
+ runtime 'net.java.dev.jna:jna-platform:5.2.0'
+ runtime 'com.h2database:h2:1.4.199'
+ runtime "commons-fileupload:commons-fileupload:1.4"
compile 'com.github.ooxi:serialized-php-parser:0.5.0'
- compile 'io.pebbletemplates:pebble-spring5:3.0.6'
+ compile 'io.pebbletemplates:pebble-spring5:3.0.8'
compile 'com.atlassian.commonmark:commonmark:0.12.1'
compile 'com.atlassian.commonmark:commonmark-ext-autolink:0.12.1'
compile 'org.tomitribe:tomitribe-http-signatures:1.1'
- compile 'com.squareup.okhttp3:okhttp:3.12.0'
- compile 'com.google.api-client:google-api-client:1.27.0'
+ compile 'com.google.api-client:google-api-client:1.28.0'
+ compile "com.kotcrab.remark:remark:1.0.0"
testCompile("org.springframework.boot:spring-boot-starter-test")
- testCompile('net.sourceforge.htmlunit:htmlunit:2.33')
+ testCompile('net.sourceforge.htmlunit:htmlunit:2.34.1')
testCompile('org.springframework.security:spring-security-test')
testCompile 'io.springfox:springfox-swagger2:2.9.2'
@@ -186,6 +190,9 @@ bootRun.dependsOn ':generateDebugKey'
compileFrontend.dependsOn 'yarn'
processResources.dependsOn 'compileFrontend'
+sourceCompatibility = JavaVersion.VERSION_11
+targetCompatibility = JavaVersion.VERSION_11
+
class GenKey extends DefaultTask {
@OutputFile
String keystore
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 521ea641..87b738cb 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ee671127..1b2b07cf 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/java-telegram-bot-api b/java-telegram-bot-api
deleted file mode 160000
-Subproject 672eabf1d52ce73ac9242b545c9893e64ba82df
diff --git a/package.json b/package.json
index 27275ee2..6f13d767 100644
--- a/package.json
+++ b/package.json
@@ -22,33 +22,32 @@
]
},
"devDependencies": {
- "@babel/core": "^7.2.0",
- "@babel/preset-env": "^7.2.0",
- "babel-loader": "^8.0.4",
- "css-loader": "^1.0.1",
- "eslint": "^5.9.0",
- "eslint-loader": "^2.1.1",
+ "@babel/core": "^7.3.4",
+ "@babel/preset-env": "^7.3.4",
+ "babel-loader": "^8.0.5",
+ "css-loader": "^2.1.1",
+ "eslint": "^5.15.1",
+ "eslint-loader": "^2.1.2",
"eslint-plugin-only-ascii": "0.0.0",
- "mini-css-extract-plugin": "^0.4.5",
+ "mini-css-extract-plugin": "^0.5.0",
"optimize-css-assets-webpack-plugin": "^5.0.1",
"postcss-loader": "^3.0.0",
- "postcss-preset-env": "^6.4.0",
+ "postcss-preset-env": "^6.6.0",
"style-loader": "^0.23.1",
- "stylelint": "^9.9.0",
+ "stylelint": "^9.10.1",
"stylelint-config-standard": "^18.2.0",
- "stylelint-webpack-plugin": "^0.10.5",
- "terser-webpack-plugin": "^1.1.0",
+ "terser-webpack-plugin": "^1.2.3",
"url-loader": "^1.1.2",
- "webpack": "^4.27.1",
- "webpack-cli": "^3.1.2"
+ "webpack": "^4.29.6",
+ "webpack-cli": "^3.2.3"
},
"dependencies": {
- "@babel/polyfill": "^7.0.0",
+ "@babel/polyfill": "^7.2.5",
"classlist.js": "^1.1.20150312",
- "element-closest": "^2.0.2",
+ "element-closest": "3.0.1",
"evil-icons": "^1.10.1",
- "formdata-polyfill": "^3.0.13",
- "url-polyfill": "^1.1.3",
+ "formdata-polyfill": "^3.0.17",
+ "url-polyfill": "^1.1.5",
"whatwg-fetch": "^3.0.0"
}
}
diff --git a/src/main/assets/embed.js b/src/main/assets/embed.js
index d4cbab8e..3b8946bf 100644
--- a/src/main/assets/embed.js
+++ b/src/main/assets/embed.js
@@ -72,8 +72,8 @@ function makeIframe(src, w, h, scrolling='no') {
}
function makeResizableToRatio(element, ratio) {
- element.dataset['ratio'] = ratio;
- makeResizable(element, w => w * element.dataset['ratio']);
+ element.setAttribute('data-ratio', ratio);
+ makeResizable(element, w => w * element.getAttribute('data-ratio'));
}
// calcHeight :: Number -> Number -- calculate element height for a given width
diff --git a/src/main/assets/scripts.js b/src/main/assets/scripts.js
index f90fe2c5..e7396c31 100644
--- a/src/main/assets/scripts.js
+++ b/src/main/assets/scripts.js
@@ -1,4 +1,4 @@
-require('element-closest');
+require('element-closest/browser');
require('classlist.js');
require('url-polyfill');
require('formdata-polyfill');
diff --git a/src/main/java/com/juick/Message.java b/src/main/java/com/juick/Message.java
index 10380826..2035d4c6 100644
--- a/src/main/java/com/juick/Message.java
+++ b/src/main/java/com/juick/Message.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2017, Juick
+ * Copyright (C) 2008-2019, Juick
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -21,15 +21,15 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.juick.adapters.SimpleDateAdapter;
import com.juick.model.Entity;
-import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
+import javax.annotation.Nonnull;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.net.URI;
import java.time.Instant;
-import java.util.ArrayList;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -45,8 +45,8 @@ public class Message implements Comparable {
private int replyto = 0;
private String text = null;
private User user = null;
- private final List<Tag> tags;
- private Instant ts;
+ private Set<Tag> tags;
+ private Instant created;
private Instant updated;
private Instant updatedAt;
private boolean unread;
@@ -81,12 +81,12 @@ public class Message implements Comparable {
private URI replyToUri;
private boolean html;
- private Set<String> recommendations;
+ private Set<User> recommendations;
private List<Entity> entities;
public Message() {
- tags = new ArrayList<>();
+ tags = new LinkedHashSet<>();
reactions = new HashSet<>();
}
@@ -120,7 +120,7 @@ public class Message implements Comparable {
}
@Override
- public int compareTo(Object obj) throws ClassCastException {
+ public int compareTo(@Nonnull Object obj) throws ClassCastException {
if (obj == this)
return 0;
@@ -180,15 +180,15 @@ public class Message implements Comparable {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC")
@XmlAttribute(name = "ts")
@XmlJavaTypeAdapter(SimpleDateAdapter.class)
- public Instant getTimestamp() {
- return ts;
+ public Instant getCreated() {
+ return created;
}
- public void setTimestamp(Instant timestamp) {
- this.ts = timestamp;
+ public void setCreated(Instant timestamp) {
+ this.created = timestamp;
}
- @XmlElement(name = "to", namespace = "http://juick.com/user")
+ @XmlTransient
public User getTo() {
return to;
}
@@ -218,14 +218,12 @@ public class Message implements Comparable {
@JsonProperty("tags")
@XmlElement(name = "tag")
- public List<Tag> getTags() {
+ public Set<Tag> getTags() {
return tags;
}
- public void setTags(List<Tag> tags) {
- this.tags.clear();
- if (CollectionUtils.isNotEmpty(tags))
- this.tags.addAll(tags);
+ public void setTags(Set<Tag> tags) {
+ this.tags = tags;
}
@XmlAttribute
@@ -333,11 +331,11 @@ public class Message implements Comparable {
this.service = service;
}
- public Set<String> getRecommendations() {
+ public Set<User> getRecommendations() {
return recommendations;
}
- public void setRecommendations(Set<String> recommendations) {
+ public void setRecommendations(Set<User> recommendations) {
this.recommendations = recommendations;
}
@@ -363,6 +361,7 @@ public class Message implements Comparable {
this.replyUri = replyUri;
}
+ @XmlAttribute(name = "html")
public boolean isHtml() {
return html;
}
@@ -371,6 +370,7 @@ public class Message implements Comparable {
this.html = html;
}
+ @XmlTransient
public URI getReplyToUri() {
return replyToUri;
}
diff --git a/src/main/java/com/juick/User.java b/src/main/java/com/juick/User.java
index 7221e416..f34f07a8 100644
--- a/src/main/java/com/juick/User.java
+++ b/src/main/java/com/juick/User.java
@@ -53,6 +53,9 @@ public class User {
private URI uri;
private Instant seen;
private boolean verified;
+ private String country;
+ private String url;
+ private String description;
public User() {
tokens = new ArrayList<>();
@@ -62,12 +65,13 @@ public class User {
@Override
public boolean equals(Object obj) {
return obj == this ||
- (obj instanceof User && ((User) obj).getUid() == this.getUid());
+ (obj instanceof User && ((User) obj).getUid() == this.getUid()
+ && ((User) obj).getUri().toString().equals(this.getUri().toString()));
}
@Override
public int hashCode() {
- return Objects.hash(uid);
+ return Objects.hash(uid, uri);
}
@Override
@@ -170,7 +174,7 @@ public class User {
@XmlTransient
@JsonIgnore
public boolean isAnonymous() {
- return false;
+ return uid == 0;
}
@Nonnull
@@ -206,6 +210,7 @@ public class User {
}
@Nonnull
+ @XmlTransient
public URI getUri() {
if (uri == null) {
uri = URI.create(StringUtils.EMPTY);
@@ -225,6 +230,7 @@ public class User {
this.seen = seen;
}
+ @XmlTransient
public boolean isVerified() {
return verified;
}
@@ -232,4 +238,28 @@ public class User {
public void setVerified(boolean verified) {
this.verified = verified;
}
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
}
diff --git a/src/main/java/com/juick/formatters/PlainTextFormatter.java b/src/main/java/com/juick/formatters/PlainTextFormatter.java
index 378a523f..41d24e93 100644
--- a/src/main/java/com/juick/formatters/PlainTextFormatter.java
+++ b/src/main/java/com/juick/formatters/PlainTextFormatter.java
@@ -57,7 +57,7 @@ public class PlainTextFormatter {
public static String formatPostSummary(Message m) {
int cropLength = 384;
- String timeAgo = pt.format(Date.from(m.getTimestamp()));
+ String timeAgo = pt.format(Date.from(m.getCreated()));
String repliesCount = m.getReplies() == 1 ? "; 1 reply" : m.getReplies() == 0 ? ""
: String.format("; %d replies", m.getReplies());
StringBuilder sb = new StringBuilder();
@@ -84,6 +84,14 @@ public class PlainTextFormatter {
return "https://juick.com/m/" + jmsg.getMid();
}
+ public static String markdownUrl(String url, String description) {
+ if (StringUtils.isNotBlank(description)) {
+ return String.format("[%s](%s)", description, url);
+ } else {
+ return url;
+ }
+ }
+
public static String formatPostNumber(com.juick.Message jmsg) {
if (jmsg.getRid() > 0) {
return String.format("%d/%d", jmsg.getMid(), jmsg.getRid());
diff --git a/src/main/java/com/juick/model/UserInfo.java b/src/main/java/com/juick/model/UserInfo.java
deleted file mode 100644
index ca5d75e0..00000000
--- a/src/main/java/com/juick/model/UserInfo.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.model;
-
-/**
- * Created by vt on 03/09/16.
- */
-public class UserInfo {
- private String fullName;
- private String country;
- private String url;
- private String description;
-
- public String getFullName() {
- return fullName;
- }
-
- public void setFullName(String fullName) {
- this.fullName = fullName;
- }
-
- public String getCountry() {
- return country;
- }
-
- public void setCountry(String country) {
- this.country = country;
- }
-
- public String getUrl() {
- return url;
- }
-
- public void setUrl(String url) {
- this.url = url;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-}
diff --git a/src/main/java/com/juick/model/facebook/User.java b/src/main/java/com/juick/model/facebook/User.java
index 80838de6..a9288fe4 100644
--- a/src/main/java/com/juick/model/facebook/User.java
+++ b/src/main/java/com/juick/model/facebook/User.java
@@ -27,98 +27,28 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class User {
private String id;
private String name;
- private String link;
- private boolean verified;
private String firstName;
private String lastName;
- private String gender;
- private String locale;
- private String timezone;
- private String updatedTime;
private String email;
public String getId() {
return id;
}
- public void setId(String id) {
- this.id = id;
- }
-
public String getName() {
return name;
}
- public void setName(String name) {
- this.name = name;
- }
-
- public String getLink() {
- return link;
- }
-
- public void setLink(String link) {
- this.link = link;
- }
-
- public boolean getVerified() {
- return verified;
- }
-
- public void setVerified(boolean verified) {
- this.verified = verified;
- }
-
@JsonProperty("first_name")
public String getFirstName() {
return firstName;
}
- public void setFirstName(String firstName) {
- this.firstName = firstName;
- }
-
- public String getGender() {
- return gender;
- }
-
- public void setGender(String gender) {
- this.gender = gender;
- }
@JsonProperty("last_name")
public String getLastName() {
return lastName;
}
- public void setLastName(String lastName) {
- this.lastName = lastName;
- }
-
- public String getLocale() {
- return locale;
- }
-
- public void setLocale(String locale) {
- this.locale = locale;
- }
-
- public String getTimezone() {
- return timezone;
- }
-
- public void setTimezone(String timezone) {
- this.timezone = timezone;
- }
-
- @JsonProperty("updated_time")
- public String getUpdatedTime() {
- return updatedTime;
- }
-
- public void setUpdatedTime(String updatedTime) {
- this.updatedTime = updatedTime;
- }
-
public String getEmail() {
return email;
}
diff --git a/src/main/java/com/juick/model/twitter/User.java b/src/main/java/com/juick/model/twitter/User.java
index 3c80eff4..22f44cf6 100644
--- a/src/main/java/com/juick/model/twitter/User.java
+++ b/src/main/java/com/juick/model/twitter/User.java
@@ -31,8 +31,4 @@ public class User {
public String getScreenName() {
return screenName;
}
-
- public void setScreenName(String screenName) {
- this.screenName = screenName;
- }
}
diff --git a/src/main/java/com/juick/model/vk/Token.java b/src/main/java/com/juick/model/vk/Token.java
index ed93a3ab..15645f99 100644
--- a/src/main/java/com/juick/model/vk/Token.java
+++ b/src/main/java/com/juick/model/vk/Token.java
@@ -17,11 +17,13 @@
package com.juick.model.vk;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Created by vitalyster on 28.11.2016.
*/
+@JsonIgnoreProperties(ignoreUnknown = true)
public class Token {
private Long userId;
private String accessToken;
@@ -32,25 +34,13 @@ public class Token {
return userId;
}
- public void setUserId(Long userId) {
- this.userId = userId;
- }
-
@JsonProperty("access_token")
public String getAccessToken() {
return accessToken;
}
- public void setAccessToken(String accessToken) {
- this.accessToken = accessToken;
- }
-
@JsonProperty("expires_in")
public String getExpiresIn() {
return expiresIn;
}
-
- public void setExpiresIn(String expiresIn) {
- this.expiresIn = expiresIn;
- }
}
diff --git a/src/main/java/com/juick/model/vk/User.java b/src/main/java/com/juick/model/vk/User.java
index aeb18285..7eb03182 100644
--- a/src/main/java/com/juick/model/vk/User.java
+++ b/src/main/java/com/juick/model/vk/User.java
@@ -17,11 +17,13 @@
package com.juick.model.vk;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Created by vitalyster on 28.11.2016.
*/
+@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
private String id;
private String firstName;
@@ -33,33 +35,17 @@ public class User {
return firstName;
}
- public void setFirstName(String firstName) {
- this.firstName = firstName;
- }
-
@JsonProperty("last_name")
public String getLastName() {
return lastName;
}
- public void setLastName(String lastName) {
- this.lastName = lastName;
- }
-
@JsonProperty("screen_name")
public String getScreenName() {
return screenName;
}
- public void setScreenName(String screenName) {
- this.screenName = screenName;
- }
-
public String getId() {
return id;
}
-
- public void setId(String id) {
- this.id = id;
- }
}
diff --git a/src/main/java/com/juick/model/vk/UsersResponse.java b/src/main/java/com/juick/model/vk/UsersResponse.java
index 67505703..d82b0c4b 100644
--- a/src/main/java/com/juick/model/vk/UsersResponse.java
+++ b/src/main/java/com/juick/model/vk/UsersResponse.java
@@ -31,8 +31,4 @@ public class UsersResponse {
public List<User> getUsers() {
return users;
}
-
- public void setUsers(List<User> users) {
- this.users = users;
- }
}
diff --git a/src/main/java/com/juick/server/ActivityPubManager.java b/src/main/java/com/juick/server/ActivityPubManager.java
index 5249f3c9..a5398325 100644
--- a/src/main/java/com/juick/server/ActivityPubManager.java
+++ b/src/main/java/com/juick/server/ActivityPubManager.java
@@ -182,9 +182,10 @@ public class ActivityPubManager implements ActivityListener, NotificationListene
cc.add(replier);
note.setCc(cc);
}
+ subscribers.addAll(note.getCc());
subscribers.forEach(acct -> {
Optional<Context> context = signatureManager.getContext(URI.create(acct));
- if (context.isPresent()) {
+ if (context.isPresent() && context.get() instanceof Person) {
Person follower = (Person)context.get();
Create create = new Create();
create.setId(note.getId());
@@ -268,7 +269,7 @@ public class ActivityPubManager implements ActivityListener, NotificationListene
note.setTo(Collections.singletonList("https://www.w3.org/ns/activitystreams#Public"));
note.setCc(Collections.singletonList(followersUri(msg.getUser())));
}
- note.setPublished(msg.getTimestamp());
+ note.setPublished(msg.getCreated());
if (StringUtils.isNotBlank(msg.getAttachmentType())) {
Image attachment = new Image();
attachment.setId(msg.getAttachment().getMedium().getUrl());
@@ -304,7 +305,7 @@ public class ActivityPubManager implements ActivityListener, NotificationListene
Person person = (Person) personContext.get();
note.getTags().add(new Mention(person.getUrl(), person.getPreferredUsername()));
List<String> cc = new ArrayList<>(note.getCc());
- cc.add(person.getUrl());
+ cc.add(person.getId());
note.setCc(cc);
}
});
diff --git a/src/main/java/com/juick/server/CommandsManager.java b/src/main/java/com/juick/server/CommandsManager.java
index fa3c5537..f6f29941 100644
--- a/src/main/java/com/juick/server/CommandsManager.java
+++ b/src/main/java/com/juick/server/CommandsManager.java
@@ -25,6 +25,7 @@ import com.juick.model.CommandResult;
import com.juick.model.TagStats;
import com.juick.server.helpers.annotation.UserCommand;
import com.juick.server.util.HttpUtils;
+import com.juick.server.www.WebApp;
import com.juick.service.*;
import com.juick.service.activities.DeleteMessageEvent;
import com.juick.service.component.*;
@@ -34,12 +35,15 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.commons.lang3.tuple.Pair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import javax.annotation.Nonnull;
import javax.inject.Inject;
+import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.*;
@@ -53,6 +57,7 @@ import java.util.stream.Collectors;
*/
@Component
public class CommandsManager {
+ private static final Logger logger = LoggerFactory.getLogger(CommandsManager.class);
@Inject
private MessagesService messagesService;
@Inject
@@ -75,6 +80,8 @@ public class CommandsManager {
private ApplicationEventPublisher applicationEventPublisher;
@Inject
private ImagesService imagesService;
+ @Inject
+ private WebApp webApp;
public CommandResult processCommand(@Nonnull User user, String data, @Nonnull URI attachment) throws Exception {
if (!user.isAnonymous()) {
@@ -121,12 +128,16 @@ public class CommandsManager {
: HttpUtils.downloadImage(attachment.toURL(), tmpDir).getHost();
attachmentType = attachmentFName.substring(attachmentFName.length() - 3);
}
+ if (StringUtils.isEmpty(body) && !haveAttachment) {
+ return CommandResult.fromString("Empty message");
+ }
int mid = messagesService.createMessage(user.getUid(), body, attachmentType, tags.getRight());
if (haveAttachment) {
String fname = String.format("%d.%s", mid, attachmentType);
imagesService.saveImageWithPreviews(attachmentFName, fname);
}
Message msg = messagesService.getMessage(mid).orElseThrow(IllegalStateException::new);
+ msg.getUser().setAvatar(webApp.getAvatarUrl(msg.getUser()));
subscriptionService.subscribeMessage(msg, user);
applicationEventPublisher.publishEvent(new MessageReadEvent(this, user, msg));
@@ -160,7 +171,7 @@ public class CommandsManager {
String body = arguments[1];
User user_to = userService.getUserByName(arguments[0]);
-
+ user_to.setAvatar(webApp.getAvatarUrl(user_to));
if (!user_to.isAnonymous()) {
if (!userService.isInBLAny(user_to.getUid(), user_from.getUid())) {
if (pmQueriesService.createPM(user_from.getUid(), user_to.getUid(), body)) {
@@ -523,12 +534,22 @@ public class CommandsManager {
String attachmentFName = null;
String attachmentType = null;
if (haveAttachment) {
- attachmentFName = attachment.getScheme().equals("juick") ? attachment.getHost()
- : HttpUtils.downloadImage(attachment.toURL(), tmpDir).getHost();
- attachmentType = attachmentFName.substring(attachmentFName.length() - 3);
+ if (attachment.getScheme().equals("juick")) {
+ attachmentFName = attachment.getHost();
+ attachmentType = attachmentFName.substring(attachmentFName.length() - 3);
+ } else {
+ try {
+ attachmentFName = HttpUtils.downloadImage(attachment.toURL(), tmpDir).getHost();
+ attachmentType = attachmentFName.substring(attachmentFName.length() - 3);
+ } catch (IOException e) {
+ logger.warn("Can not download {}", attachment.toURL());
+ }
+ }
}
- int newrid = messagesService.createReply(mid, rid, user, txt, attachmentType);
- if (haveAttachment) {
+ boolean attachmentProcessed = !haveAttachment || StringUtils.isNotEmpty(attachmentType);
+ String messageText = attachmentProcessed ? txt : String.format("%s %s", txt, attachment.toASCIIString());
+ int newrid = messagesService.createReply(mid, rid, user, messageText, attachmentType);
+ if (haveAttachment && attachmentProcessed) {
String fname = String.format("%d-%d.%s", mid, newrid, attachmentType);
imagesService.saveImageWithPreviews(attachmentFName, fname);
}
@@ -537,6 +558,7 @@ public class CommandsManager {
Message original = messagesService.getMessage(mid).orElseThrow(IllegalStateException::new);
subscriptionService.subscribeMessage(original, user);
Message reply = messagesService.getReply(mid, newrid);
+ reply.getUser().setAvatar(webApp.getAvatarUrl(reply.getUser()));
applicationEventPublisher.publishEvent(new MessageEvent(this, reply, subscriptionService.getUsersSubscribedToComments(original, reply)));
return CommandResult.build(reply,"Reply posted.\n#" + mid + "/" + newrid + " "
+ "https://juick.com/m/" + mid + "#" + newrid,
diff --git a/src/main/java/com/juick/server/KeystoreManager.java b/src/main/java/com/juick/server/KeystoreManager.java
index 67a24f11..3ae7b866 100644
--- a/src/main/java/com/juick/server/KeystoreManager.java
+++ b/src/main/java/com/juick/server/KeystoreManager.java
@@ -19,20 +19,17 @@ import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.stream.Collectors;
-@Component
public class KeystoreManager {
private static final Logger logger = LoggerFactory.getLogger("com.juick.server");
- @Value("${keystore:juick.p12}")
- private String keystore;
- @Value("${keystore_password:secret}")
+
private String keystorePassword;
private KeyStore ks;
private KeyManagerFactory kmf;
- @PostConstruct
- public void init() {
+ public KeystoreManager(String keystore, String keystorePassword) {
+ this.keystorePassword = keystorePassword;
try (InputStream ksIs = new FileInputStream(keystore)) {
ks = KeyStore.getInstance("PKCS12");
ks.load(ksIs, keystorePassword.toCharArray());
diff --git a/src/main/java/com/juick/server/ServerManager.java b/src/main/java/com/juick/server/ServerManager.java
index 7a95ec43..46faf9eb 100644
--- a/src/main/java/com/juick/server/ServerManager.java
+++ b/src/main/java/com/juick/server/ServerManager.java
@@ -16,7 +16,6 @@
*/
package com.juick.server;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.juick.Message;
import com.juick.User;
@@ -24,25 +23,18 @@ import com.juick.model.AnonymousUser;
import com.juick.service.MessagesService;
import com.juick.service.SubscriptionService;
import com.juick.service.UserService;
-import com.juick.service.component.LikeEvent;
-import com.juick.service.component.MessageEvent;
-import com.juick.service.component.MessageReadEvent;
-import com.juick.service.component.NotificationListener;
-import com.juick.service.component.PingEvent;
-import com.juick.service.component.SubscribeEvent;
-import com.juick.service.component.TopEvent;
+import com.juick.service.component.*;
import com.juick.util.MessageUtils;
+import org.apache.commons.collections4.ListUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
-import org.springframework.web.socket.TextMessage;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -62,8 +54,6 @@ public class ServerManager implements NotificationListener {
@Inject
private MessagesService messagesService;
@Inject
- private WebsocketManager wsHandler;
- @Inject
private SubscriptionService subscriptionService;
@Inject
private UserService userService;
@@ -81,96 +71,15 @@ public class ServerManager implements NotificationListener {
private void onJuickPM(final User to, final com.juick.Message jmsg) {
- try {
- String json = jsonMapper.writeValueAsString(jmsg);
- synchronized (wsHandler.getClients()) {
- wsHandler.getClients().stream().filter(c ->
- (!c.legacy && c.visitor.getUid() == to.getUid()) || c.visitor.equals(serviceUser))
- .forEach(c -> {
- try {
- logger.debug("sending pm to {}", c.visitor.getUid());
- c.sendMessage(new TextMessage(json));
- } catch (IOException e) {
- logger.warn("ws error", e);
- }
- });
- }
- } catch (JsonProcessingException e) {
- logger.warn("Invalid JSON", e);
- }
- messageEvent(jmsg, Collections.singletonList(to));
+ messageEvent(jmsg, Arrays.asList(to, jmsg.getUser()));
}
private void onJuickMessagePost(final com.juick.Message jmsg, List<User> subscribedUsers) {
- try {
- String json = jsonMapper.writeValueAsString(jmsg);
- List<Integer> uids = subscribedUsers
- .stream().map(User::getUid).collect(Collectors.toList());
- synchronized (wsHandler.getClients()) {
- wsHandler.getClients().stream().filter(c ->
- (!c.legacy && c.visitor.isAnonymous()) // anonymous users
- || c.visitor.equals(serviceUser) // services
- || (!c.legacy && uids.contains(c.visitor.getUid()))) // subscriptions
- .forEach(c -> {
- try {
- logger.debug("sending message to {}", c.visitor.getUid());
- c.sendMessage(new TextMessage(json));
- } catch (IOException e) {
- logger.warn("ws error", e);
- }
- });
- wsHandler.getClients().stream().filter(c ->
- c.legacy && c.allMessages) // legacy all posts
- .forEach(c -> {
- try {
- logger.debug("sending message to legacy client {}", c.visitor.getUid());
- c.sendMessage(new TextMessage(json));
- } catch (IOException e) {
- logger.warn("ws error", e);
- }
- });
- }
- } catch (JsonProcessingException e) {
- logger.warn("Invalid JSON", e);
- }
messageEvent(jmsg, subscribedUsers);
messageEvent(jmsg, Collections.singletonList(AnonymousUser.INSTANCE));
}
private void onJuickMessageReply(final com.juick.Message jmsg, final List<User> subscribedUsers) {
- try {
-
- String json = jsonMapper.writeValueAsString(jmsg);
- List<Integer> threadUsers =
- subscribedUsers
- .stream().map(User::getUid).collect(Collectors.toList());
- synchronized (wsHandler.getClients()) {
- wsHandler.getClients().stream().filter(c ->
- (!c.legacy && c.visitor.isAnonymous()) // anonymous users
- || c.visitor.equals(serviceUser) // services
- || (!c.legacy && threadUsers.contains(c.visitor.getUid()))) // subscriptions
- .forEach(c -> {
- try {
- logger.debug("sending reply to {}", c.visitor.getUid());
- c.sendMessage(new TextMessage(json));
- } catch (IOException e) {
- logger.warn("ws error", e);
- }
- });
- wsHandler.getClients().stream().filter(c ->
- (c.legacy && c.allReplies) || (c.legacy && c.MID == jmsg.getMid())) // legacy replies
- .forEach(c -> {
- try {
- logger.debug("sending reply to legacy client {}", c.visitor.getUid());
- c.sendMessage(new TextMessage(json));
- } catch (IOException e) {
- logger.warn("ws error", e);
- }
- });
- }
- } catch (JsonProcessingException e) {
- logger.warn("Invalid JSON", e);
- }
messageEvent(jmsg, subscribedUsers);
messageEvent(jmsg, Collections.singletonList(AnonymousUser.INSTANCE));
}
@@ -178,7 +87,7 @@ public class ServerManager implements NotificationListener {
@Override
public void processMessageEvent(MessageEvent event) {
com.juick.Message jmsg = event.getMessage();
- List<User> subscribedUsers = event.getUsers();
+ List<User> subscribedUsers = ListUtils.union(event.getUsers(), Collections.singletonList(jmsg.getUser()));
if (jmsg.isService()) {
readEvent(jmsg, Collections.singletonList(serviceUser));
return;
@@ -186,16 +95,14 @@ public class ServerManager implements NotificationListener {
if (MessageUtils.isPM(jmsg)) {
onJuickPM(jmsg.getTo(), jmsg);
} else if (!MessageUtils.isReply(jmsg)) {
- // to get full message with attachment, etc.
- onJuickMessagePost(messagesService.getMessage(jmsg.getMid()).orElseThrow(IllegalStateException::new), subscribedUsers);
+ onJuickMessagePost(jmsg, subscribedUsers);
} else {
// to get quote and attachment
Message op = messagesService.getMessage(jmsg.getMid()).orElseThrow(IllegalStateException::new);
- com.juick.Message reply = messagesService.getReply(jmsg.getMid(), jmsg.getRid());
- subscriptionService.getUsersSubscribedToComments(op, reply, true).stream()
- .filter(u -> userService.isReplyToBL(u, reply))
- .forEach(b -> messagesService.setLastReadComment(b, reply.getMid(), reply.getRid()));
- onJuickMessageReply(reply, subscribedUsers);
+ subscriptionService.getUsersSubscribedToComments(op, jmsg, true).stream()
+ .filter(u -> userService.isReplyToBL(u, jmsg))
+ .forEach(b -> messagesService.setLastReadComment(b, jmsg.getMid(), jmsg.getRid()));
+ onJuickMessageReply(jmsg, subscribedUsers);
}
messageEvent(jmsg, Collections.singletonList(serviceUser));
}
@@ -226,15 +133,6 @@ public class ServerManager implements NotificationListener {
serviceMessage.setUser(user);
serviceMessage.setMid(source.getMid());
serviceMessage.setUnread(false);
- wsHandler.getClients().stream().filter(c ->
- (!c.legacy && c.visitor == user) || c.visitor.equals(serviceUser)
- ).forEach(u -> {
- try {
- u.sendMessage(new TextMessage(jsonMapper.writeValueAsString(serviceMessage)));
- } catch (IOException e) {
- logger.error("JSON error", e);
- }
- });
readEvent(serviceMessage, Collections.singletonList(serviceUser));
}
diff --git a/src/main/java/com/juick/server/SignatureManager.java b/src/main/java/com/juick/server/SignatureManager.java
index b3b7a301..755575ce 100644
--- a/src/main/java/com/juick/server/SignatureManager.java
+++ b/src/main/java/com/juick/server/SignatureManager.java
@@ -1,14 +1,17 @@
package com.juick.server;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.juick.User;
+import com.juick.model.AnonymousUser;
import com.juick.server.api.activity.model.Context;
import com.juick.server.api.activity.model.objects.Person;
import com.juick.server.api.webfinger.model.Account;
import com.juick.server.api.webfinger.model.Link;
+import com.juick.service.UserService;
import com.juick.util.DateFormattersHolder;
+import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
@@ -41,7 +44,7 @@ public class SignatureManager {
@Inject
private ObjectMapper jsonMapper;
@Inject
- private ApplicationEventPublisher applicationEventPublisher;
+ private UserService userService;
@Inject
private RestTemplate apClient;
@@ -50,56 +53,89 @@ public class SignatureManager {
URI inbox = uriComponentsBuilder.build().toUri();
Instant now = Instant.now();
String requestDate = DateFormattersHolder.getHttpDateFormatter().format(now);
- Signature templateSignature = new Signature(from.getPublicKey().getId(), "rsa-sha256", null,
- "(request-target)", "host", "date");
- Signer signer = new Signer(keystoreManager.getPrivateKey(), templateSignature);
- Map<String, String> headers = new HashMap<>();
- headers.put("host", inbox.getHost());
- headers.put("date", requestDate);
- Signature signature = signer.sign("POST", inbox.getPath(), headers);
+ String host = inbox.getPort() > 0 ? String.format("%s:%d", inbox.getHost(), inbox.getPort()) : inbox.getHost();
+ String signatureString = addSignature(from, host, "POST", inbox.getPath(), requestDate);
+
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Content-Type", Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE);
requestHeaders.add("Date", requestDate);
- requestHeaders.add("Signature", signature.toString().substring(10));
+ requestHeaders.add("Host", host);
+ requestHeaders.add("Signature", signatureString);
HttpEntity<Context> request = new HttpEntity<>(Context.build(data), requestHeaders);
- //boolean valid = verifySignature(Signature.fromString(requestHeaders.getFirst("Signature")),
- // keystoreManager.getPublicKey(), "POST", inbox.getPath(), headers);
logger.info("Sending context: {}", jsonMapper.writeValueAsString(data));
logger.info("Request date: {}", requestDate);
ResponseEntity<Void> response = apClient.postForEntity(inbox, request, Void.class);
logger.info("accepted follower: {}", response.getStatusCodeValue());
+ }
+ public String addSignature(Person from, String host, String method, String path, String dateString) throws IOException {
+ return addSignature(from, host, method, path, dateString, keystoreManager);
}
- public boolean verifySignature(String signatureString, URI actor, String method, String path, Map<String, String> headers) {
- Optional<Context> context = getContext(actor);
+
+ public String addSignature(Person from, String host, String method, String path, String dateString, KeystoreManager keystoreManager) throws IOException {
+ Signature templateSignature = new Signature(from.getPublicKey().getId(), "rsa-sha256", null,
+ "(request-target)", "host", "date");
+ Map<String, String> headers = new HashMap<>();
+ headers.put("host", host);
+ headers.put("date", dateString);
+ Signer signer = new Signer(keystoreManager.getPrivateKey(), templateSignature);
+ Signature signature = signer.sign(method, path, headers);
+ // remove "Signature: " from result
+ return signature.toString().substring(10);
+ }
+
+ public User verifySignature(String method, String path, Map<String, String> headers) {
+ String signatureString = headers.get("signature");
+ logger.info("Signature: {}", signatureString);
+ Signature signature = Signature.fromString(signatureString);
+ Optional<Context> context = getContext(UriComponentsBuilder.fromUriString(signature.getKeyId())
+ .fragment(null).build().toUri());
if (context.isPresent() && context.get() instanceof Person) {
Person person = (Person) context.get();
Key key = KeystoreManager.publicKeyOf(person);
- Verifier verifier = new Verifier(key, Signature.fromString(signatureString));
+
+ Verifier verifier = new Verifier(key, signature);
try {
boolean result = verifier.verify(method, path, headers);
- logger.info("signature is valid: {}", result);
- return result;
+ logger.info("signature of {} is valid: {}", signature.getKeyId(), result);
+ if (result) {
+ User user = new User();
+ user.setUri(URI.create(person.getId()));
+ if (key.equals(keystoreManager.getPublicKey())) {
+ return userService.getUserByName(person.getName());
+ }
+ return user;
+ } else {
+ return AnonymousUser.INSTANCE;
+ }
} catch (NoSuchAlgorithmException | SignatureException | IOException e) {
- logger.info("signature exception", e);
- return false;
+ logger.warn("Invalid signature {}", signatureString);
}
+ } else {
+ logger.warn("Unknown keyId");
}
- logger.info("person not found");
- return false;
+ return AnonymousUser.INSTANCE;
}
public Optional<Context> getContext(URI contextUri) {
- Context context = apClient.getForEntity(contextUri, Context.class).getBody();
- if (context == null) {
- logger.warn("Cannot identify {}", contextUri);
- return Optional.empty();
+ try {
+ Context context = apClient.getForEntity(contextUri, Context.class).getBody();
+ if (context == null) {
+ logger.warn("Cannot identify {}", contextUri);
+ return Optional.empty();
+ }
+ return Optional.of(context);
+ } catch (Exception e) {
+ logger.warn("REST Exception on {}: {}", contextUri, e.getMessage());
}
- return Optional.of(context);
+ return Optional.empty();
}
public Optional<Context> discoverPerson(String acct) {
- Jid acctId = Jid.of(acct);
+ String[] accountParts = acct.split(":", 2);
+ String account = accountParts[0];
+ int port = accountParts.length > 1 ? Integer.valueOf(accountParts[1]) : 80;
+ Jid acctId = Jid.of(account);
URI resourceUri = UriComponentsBuilder.fromUriString(
- String.format("https://%s/.well-known/webfinger?resource=acct:%s", acctId.getDomain(), acct)).build().toUri();
+ String.format("http://%s:%d/.well-known/webfinger?resource=acct:%s", acctId.getDomain(), port, account)).build().toUri();
Account acctData = apClient.getForEntity(resourceUri, Account.class).getBody();
if (acctData != null) {
for (Link l : acctData.getLinks()) {
diff --git a/src/main/java/com/juick/server/WebsocketManager.java b/src/main/java/com/juick/server/WebsocketManager.java
deleted file mode 100644
index 1b62b984..00000000
--- a/src/main/java/com/juick/server/WebsocketManager.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server;
-
-import com.juick.User;
-import com.juick.model.AnonymousUser;
-import com.juick.model.CommandResult;
-import com.juick.server.util.HttpForbiddenException;
-import com.juick.server.util.HttpNotFoundException;
-import com.juick.service.MessagesService;
-import com.juick.service.UserService;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.http.HttpHeaders;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-import org.springframework.web.socket.CloseStatus;
-import org.springframework.web.socket.PingMessage;
-import org.springframework.web.socket.TextMessage;
-import org.springframework.web.socket.WebSocketSession;
-import org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator;
-import org.springframework.web.socket.handler.TextWebSocketHandler;
-import org.springframework.web.util.UriComponents;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import javax.annotation.Nonnull;
-import javax.inject.Inject;
-import java.io.IOException;
-import java.net.URI;
-import java.time.Instant;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * Created by vitalyster on 28.06.2016.
- */
-@Component
-public class WebsocketManager extends TextWebSocketHandler {
- private static final Logger logger = LoggerFactory.getLogger(WebsocketManager.class);
-
- private final List<UserSession> clients = new CopyOnWriteArrayList<>();
-
- @Inject
- private UserService userService;
- @Inject
- private MessagesService messagesService;
- @Inject
- private CommandsManager commandsManager;
-
-
- @Override
- public void afterConnectionEstablished(WebSocketSession session) {
-
- UserSession userSession = new UserSession(session);
- URI hLocation = session.getUri();
-
- // Auth
- UriComponents uriComponents = UriComponentsBuilder.fromUri(hLocation).build();
- List<String> hash = uriComponents.getQueryParams().get("hash");
- if (hash != null && hash.get(0).length() == 16) {
- userSession.visitor = userService.getUserByHash(hash.get(0));
- } else {
- logger.debug("wrong hash for {} from {}", userSession.visitor.getUid(), userSession);
- }
-
- if (hLocation.getPath().equals("/ws/")) {
- logger.debug("user {} connected", userSession.visitor.getUid());
- } else if (hLocation.getPath().equals("/ws/_all")) {
- logger.debug("user {} connected to legacy _all ({})", userSession.visitor.getUid(), hLocation.getPath());
- userSession.legacy = true;
- userSession.allMessages = true;
- } else if (hLocation.getPath().equals("/ws/_replies")) {
- logger.debug("user {} connected to legacy _replies ({})", userSession.visitor.getUid(), hLocation.getPath());
- userSession.legacy = true;
- userSession.allReplies = true;
- } else if (hLocation.getPath().matches("^/ws/(\\d)+$")) {
- int MID = NumberUtils.toInt(hLocation.getPath().substring(4), 0);
- if (MID > 0) {
- if (messagesService.canViewThread(MID, userSession.visitor.getUid())) {
- logger.debug("user {} connected to legacy thread ({}) from {}", userSession.visitor.getUid(), MID, userSession);
- userSession.legacy = true;
- userSession.MID = MID;
- } else {
- throw new HttpForbiddenException();
- }
- }
- } else {
- throw new HttpNotFoundException();
- }
- clients.add(userSession);
- logger.debug("{} clients connected", clients.size());
- }
-
- @Override
- public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
- logger.debug("session closed with status {}: {}", status.getCode(), status.getReason());
- clients.removeIf(c -> c.getDelegate().getId().equals(session.getId()));
- logger.debug("{} clients connected", clients.size());
- }
-
- @Scheduled(fixedRate = 30000)
- public void ping() {
- clients.forEach(c -> {
- try {
- if (c.isOpen()) {
- c.sendMessage(new PingMessage());
- }
- } catch (IOException e) {
- logger.error("WebSocket PING exception", e);
- }
- });
- }
-
- @Override
- protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
- UserSession ws = clients.stream().filter(c -> c.getDelegate().equals(session))
- .findFirst().orElseThrow(IllegalStateException::new);
- if (!ws.visitor.isAnonymous()) {
- String command = message.getPayload().trim();
- if (StringUtils.isNotEmpty(command)) {
- CommandResult result = commandsManager.processCommand(ws.visitor, command, URI.create(""));
- ws.sendMessage(new TextMessage(result.getText()));
- }
- } else {
- ws.sendMessage(new TextMessage("Authorization required"));
- }
- }
-
- public List<UserSession> getClients() {
- return clients;
- }
-
- class UserSession extends ConcurrentWebSocketSessionDecorator {
- User visitor;
- int MID;
- boolean allMessages;
- boolean allReplies;
- Instant tsConnected;
- Instant tsLastData;
- boolean legacy;
-
- UserSession(WebSocketSession session) {
- super(session, 60000, 65536);
- this.visitor = AnonymousUser.INSTANCE;
- tsConnected = tsLastData = Instant.now();
- }
-
- @Nonnull
- @Override
- public String toString() {
- HttpHeaders headers = getHandshakeHeaders();
- return headers.getOrDefault("X-Real-IP",
- Collections.singletonList(getRemoteAddress().toString())).get(0);
- }
- }
-}
diff --git a/src/main/java/com/juick/server/XMPPConnection.java b/src/main/java/com/juick/server/XMPPManager.java
index f77b2354..51b3b04e 100644
--- a/src/main/java/com/juick/server/XMPPConnection.java
+++ b/src/main/java/com/juick/server/XMPPManager.java
@@ -19,14 +19,13 @@ package com.juick.server;
import com.juick.User;
import com.juick.formatters.PlainTextFormatter;
-import com.juick.server.www.WebApp;
-import com.juick.service.component.*;
import com.juick.model.CommandResult;
-import com.juick.model.UserInfo;
+import com.juick.server.www.WebApp;
import com.juick.server.xmpp.iq.MessageQuery;
-import com.juick.server.xmpp.s2s.BasicXmppSession;
-import com.juick.server.xmpp.s2s.StanzaListener;
-import com.juick.service.*;
+import com.juick.service.MessagesService;
+import com.juick.service.PMQueriesService;
+import com.juick.service.UserService;
+import com.juick.service.component.*;
import com.juick.util.MessageUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FilenameUtils;
@@ -35,12 +34,17 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.ApplicationEventPublisher;
import rocks.xmpp.addr.Jid;
import rocks.xmpp.core.XmppException;
+import rocks.xmpp.core.session.Extension;
import rocks.xmpp.core.session.XmppSession;
+import rocks.xmpp.core.session.XmppSessionConfiguration;
+import rocks.xmpp.core.session.debug.LogbackDebugger;
import rocks.xmpp.core.stanza.AbstractIQHandler;
-import rocks.xmpp.core.stanza.model.*;
+import rocks.xmpp.core.stanza.model.IQ;
+import rocks.xmpp.core.stanza.model.Message;
+import rocks.xmpp.core.stanza.model.Presence;
+import rocks.xmpp.core.stanza.model.StanzaError;
import rocks.xmpp.core.stanza.model.client.ClientMessage;
import rocks.xmpp.core.stanza.model.client.ClientPresence;
import rocks.xmpp.core.stanza.model.errors.Condition;
@@ -57,23 +61,19 @@ import rocks.xmpp.extensions.receipts.MessageDeliveryReceiptsManager;
import rocks.xmpp.extensions.vcard.temp.model.VCard;
import rocks.xmpp.extensions.version.SoftwareVersionManager;
import rocks.xmpp.extensions.version.model.SoftwareVersion;
-import rocks.xmpp.util.XmppUtils;
import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
-import javax.xml.bind.JAXBException;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
import java.io.IOException;
-import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.time.Duration;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
@@ -83,14 +83,12 @@ import java.util.concurrent.ExecutorService;
/**
* @author ugnich
*/
-public class XMPPConnection implements StanzaListener, NotificationListener {
+public class XMPPManager implements NotificationListener {
private static final Logger logger = LoggerFactory.getLogger("com.juick.server.xmpp");
private ExternalComponent router;
@Inject
- private XMPPServer xmpp;
- @Inject
private CommandsManager commandsManager;
@Value("${xmppbot_jid:juick@localhost}")
private Jid jid;
@@ -98,6 +96,8 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
private String componentName;
@Value("${component_port:5347}")
private int componentPort;
+ @Value("${component_host:localhost}")
+ private String componentHost;
@Value("${xmpp_password:secret}")
private String password;
@Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
@@ -110,9 +110,7 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
@Inject
private PMQueriesService pmQueriesService;
@Inject
- private BasicXmppSession session;
- @Inject
- private ExecutorService service;
+ private ExecutorService executorService;
@Value("${service_user:juick}")
private String serviceUsername;
@Inject
@@ -123,8 +121,12 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
@PostConstruct
public void init() {
logger.info("stream router start connecting to {}", componentPort);
- xmpp.addStanzaListener(this);
- router = ExternalComponent.create(componentName, password, session.getConfiguration(), "localhost", componentPort);
+ XmppSessionConfiguration configuration = XmppSessionConfiguration.builder()
+ .extensions(Extension.of(com.juick.Message.class), Extension.of(MessageQuery.class))
+ .debugger(LogbackDebugger.class)
+ .defaultResponseTimeout(Duration.ofMillis(120000))
+ .build();
+ router = ExternalComponent.create(componentName, password, configuration, componentHost, componentPort);
ServiceDiscoveryManager serviceDiscoveryManager = router.getManager(ServiceDiscoveryManager.class);
serviceDiscoveryManager.addIdentity(Identity.clientBot().withName("Juick"));
EntityCapabilitiesManager entityCapabilitiesManager = router.getManager(EntityCapabilitiesManager.class);
@@ -164,7 +166,7 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
}
User user = userService.getUserByName(iq.getTo().getLocal());
if (!user.isAnonymous()) {
- UserInfo info = userService.getUserInfo(user);
+ User info = userService.getUserInfo(user);
VCard userVCard = new VCard();
userVCard.setFormattedName(info.getFullName());
userVCard.setNickname(user.getName());
@@ -187,13 +189,6 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
router.send(result);
}
});
- router.addInboundIQListener(e -> {
- IQ iq = e.getIQ();
- Jid jid = iq.getTo();
- if (!jid.getDomain().equals(this.jid.getDomain())) {
- router.send(iq);
- }
- });
FileTransferManager fileTransferManager = router.getManager(FileTransferManager.class);
fileTransferManager.addFileTransferOfferListener(e -> {
try {
@@ -261,7 +256,7 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
router.addInboundPresenceListener(event -> {
incomingPresence(event.getPresence());
});
- service.submit(() -> {
+ executorService.submit(() -> {
try {
router.connect();
} catch (XmppException e) {
@@ -271,16 +266,6 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
serviceUser = userService.getUserByName(serviceUsername);
}
- private String stanzaToString(Stanza stanza) throws XMLStreamException, JAXBException {
- StringWriter stanzaWriter = new StringWriter();
- XMLStreamWriter xmppStreamWriter = XmppUtils.createXmppStreamWriter(
- router.getConfiguration().getXmlOutputFactory().createXMLStreamWriter(stanzaWriter));
- router.createMarshaller().marshal(stanza, xmppStreamWriter);
- xmppStreamWriter.flush();
- xmppStreamWriter.close();
- return stanzaWriter.toString();
- }
-
private void sendJuickMessage(com.juick.Message jmsg, List<User> users) {
List<String> jids = new ArrayList<>();
@@ -319,7 +304,7 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
}
}
- public void sendJuickComment(com.juick.Message jmsg, List<User> users) {
+ private void sendJuickComment(com.juick.Message jmsg, List<User> users) {
String replyQuote;
String replyTo;
@@ -569,7 +554,6 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
}
public ClientMessage incomingMessage(Message msg) {
- ClientMessage result = null;
if (msg.getType() != null && msg.getType().equals(Message.Type.ERROR)) {
StanzaError error = msg.getError();
if (error != null && error.getCondition().equals(Condition.RESOURCE_CONSTRAINT)) {
@@ -598,19 +582,10 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
} catch (Exception e1) {
logger.warn("message exception", e1);
}
- } else if (to.getDomain().endsWith(jid.getDomain()) && (to.getDomain().equals(jid.getDomain())
- || to.getDomain().endsWith("." + jid.getDomain()))) {
- if (logger.isInfoEnabled()) {
- try {
- logger.info("unhandled message: {}", stanzaToString(msg));
- } catch (JAXBException | XMLStreamException ex) {
- logger.error("JAXB exception", ex);
- }
- }
- } else {
- return ClientMessage.from(msg);
}
- return result;
+ ClientMessage errorMessage = ClientMessage.from(msg);
+ errorMessage.setError(new StanzaError(StanzaError.Type.CANCEL, Condition.ITEM_NOT_FOUND));
+ return errorMessage;
}
private ClientMessage incomingMessageJuick(User user_from, Jid from, String to, String command, @Nonnull URI attachment) {
if (StringUtils.isBlank(command) && attachment.toString().isEmpty()) {
@@ -646,11 +621,6 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
return null;
}
- @Override
- public void stanzaReceived(Stanza xmlValue) {
- router.send(xmlValue);
- }
-
private void broadcastPresence(Presence.Type type) {
Presence presence = new Presence();
presence.setFrom(jid);
@@ -674,8 +644,4 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
router.close();
}
}
-
- public ExternalComponent getRouter() {
- return router;
- }
}
diff --git a/src/main/java/com/juick/server/XMPPServer.java b/src/main/java/com/juick/server/XMPPServer.java
deleted file mode 100644
index 86ab6a78..00000000
--- a/src/main/java/com/juick/server/XMPPServer.java
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server;
-
-import com.juick.server.xmpp.router.StreamError;
-import com.juick.server.xmpp.s2s.*;
-import com.juick.service.UserService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.xmlpull.v1.XmlPullParserException;
-import rocks.xmpp.addr.Jid;
-import rocks.xmpp.core.stanza.model.Stanza;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-import javax.net.ssl.*;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-import java.io.IOException;
-import java.io.StringReader;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.SecureRandom;
-import java.security.cert.*;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * @author ugnich
- */
-public class XMPPServer implements ConnectionListener {
- private static final Logger logger = LoggerFactory.getLogger("com.juick.server.xmpp");
-
- private static final int TIMEOUT_MINUTES = 15;
-
- @Inject
- public ExecutorService service;
- @Value("${hostname:localhost}")
- private Jid jid;
- @Value("${s2s_port:5269}")
- private int s2sPort;
- @Value("${broken_ssl_hosts:}")
- public String[] brokenSSLhosts;
- @Value("${banned_hosts:}")
- public String[] bannedHosts;
-
- private final List<ConnectionIn> inConnections = new CopyOnWriteArrayList<>();
- private final Map<ConnectionOut, Optional<Socket>> outConnections = new ConcurrentHashMap<>();
- private final List<CacheEntry> outCache = new CopyOnWriteArrayList<>();
- private final List<StanzaListener> stanzaListeners = new CopyOnWriteArrayList<>();
- private final AtomicBoolean closeFlag = new AtomicBoolean(false);
-
- SSLContext sc;
- CertificateFactory cf;
- CertPathValidator cpv;
- PKIXParameters params;
- private TrustManager[] trustAllCerts = new TrustManager[]{
- new X509TrustManager() {
- public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
- }
-
- public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
- }
-
- public java.security.cert.X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
- }
- };
- private boolean tlsConfigured = false;
-
-
- private ServerSocket listener;
-
- @Inject
- private BasicXmppSession session;
- @Inject
- private UserService userService;
- @Inject
- private KeystoreManager keystoreManager;
-
- @PostConstruct
- public void init() throws KeyStoreException {
- closeFlag.set(false);
- try {
- sc = SSLContext.getInstance("TLSv1.2");
- sc.init(keystoreManager.getKeymanagerFactory().getKeyManagers(), trustAllCerts, new SecureRandom());
- TrustManagerFactory trustManagerFactory =
- TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- Set<TrustAnchor> ca = new HashSet<>();
- trustManagerFactory.init((KeyStore)null);
- Arrays.stream(trustManagerFactory.getTrustManagers()).forEach(t -> Arrays.stream(((X509TrustManager)t).getAcceptedIssuers()).forEach(cert -> ca.add(new TrustAnchor(cert, null))));
- params = new PKIXParameters(ca);
- params.setRevocationEnabled(false);
- cpv = CertPathValidator.getInstance("PKIX");
- cf = CertificateFactory.getInstance( "X.509" );
- tlsConfigured = true;
- } catch (Exception e) {
- logger.warn("tls unavailable");
- }
- service.submit(() -> {
- try {
- listener = new ServerSocket(s2sPort);
- logger.info("s2s listener ready");
- while (!listener.isClosed()) {
- if (Thread.currentThread().isInterrupted()) break;
- Socket socket = listener.accept();
- ConnectionIn client = new ConnectionIn(this, socket);
- addConnectionIn(client);
- service.submit(client);
- }
- } catch (SocketException e) {
- // shutdown
- } catch (IOException | XmlPullParserException e) {
- logger.warn("xmpp exception", e);
- }
- });
- }
-
- public void addConnectionIn(ConnectionIn c) {
- c.setListener(this);
- inConnections.add(c);
- }
-
- public void addConnectionOut(ConnectionOut c, Optional<Socket> socket) {
- c.setListener(this);
- outConnections.put(c, socket);
- }
-
- public void removeConnectionIn(ConnectionIn c) {
- inConnections.remove(c);
- }
-
- public void removeConnectionOut(ConnectionOut c) {
- outConnections.remove(c);
- }
-
- public String getFromCache(Jid to) {
- final String[] cache = new String[1];
- outCache.stream().filter(c -> c.hostname != null && c.hostname.equals(to)).findFirst().ifPresent(c -> {
- cache[0] = c.xml;
- outCache.remove(c);
- });
- return cache[0];
- }
-
- public Optional<ConnectionOut> getConnectionOut(Jid hostname, boolean needReady) {
- return outConnections.keySet().stream().filter(c -> c.to != null &&
- c.to.equals(hostname) && (!needReady || c.streamReady)).findFirst();
- }
-
- public Optional<ConnectionIn> getConnectionIn(String streamID) {
- return inConnections.stream().filter(c -> c.streamID != null && c.streamID.equals(streamID)).findFirst();
- }
-
- public void sendOut(Jid hostname, String xml) {
- boolean haveAnyConn = false;
-
- ConnectionOut connOut = null;
- for (ConnectionOut c : outConnections.keySet()) {
- if (c.to != null && c.to.equals(hostname)) {
- if (c.streamReady) {
- connOut = c;
- break;
- } else {
- haveAnyConn = true;
- break;
- }
- }
- }
- if (connOut != null) {
- connOut.send(xml);
- return;
- }
-
- boolean haveCache = false;
- for (CacheEntry c : outCache) {
- if (c.hostname != null && c.hostname.equals(hostname)) {
- c.xml += xml;
- c.updated = Instant.now();
- haveCache = true;
- break;
- }
- }
- if (!haveCache) {
- outCache.add(new CacheEntry(hostname, xml));
- }
-
- if (!haveAnyConn && !closeFlag.get()) {
- try {
- createDialbackConnection(hostname.toEscapedString(), null, null);
- } catch (Exception e) {
- logger.warn("dialback error", e);
- }
- }
- }
-
- void createDialbackConnection(String to, String checkSID, String dbKey) throws Exception {
- ConnectionOut connectionOut = new ConnectionOut(getJid(), Jid.of(to), null, null, checkSID, dbKey);
- addConnectionOut(connectionOut, Optional.empty());
- service.submit(() -> {
- try {
- Socket socket = new Socket();
- socket.connect(DNSQueries.getServerAddress(to));
- connectionOut.setInputStream(socket.getInputStream());
- connectionOut.setOutputStream(socket.getOutputStream());
- addConnectionOut(connectionOut, Optional.of(socket));
- connectionOut.connect();
- } catch (IOException e) {
- logger.info("dialback to " + to + " exception", e);
- }
- });
- }
-
- public void startDialback(Jid from, String streamId, String dbKey) throws Exception {
- Optional<ConnectionOut> c = getConnectionOut(from, false);
- if (c.isPresent()) {
- c.get().sendDialbackVerify(streamId, dbKey);
- } else {
- createDialbackConnection(from.toEscapedString(), streamId, dbKey);
- }
- }
-
- public void addStanzaListener(StanzaListener listener) {
- stanzaListeners.add(listener);
- }
-
- public void onStanzaReceived(String xmlValue) {
- logger.info("S2S: {}", xmlValue);
- Stanza stanza = parse(xmlValue);
- stanzaListeners.forEach(l -> l.stanzaReceived(stanza));
- }
-
- public BasicXmppSession getSession() {
- return session;
- }
-
- public List<ConnectionIn> getInConnections() {
- return inConnections;
- }
-
- public Map<ConnectionOut, Optional<Socket>> getOutConnections() {
- return outConnections;
- }
-
- @Override
- public boolean isTlsAvailable() {
- return tlsConfigured;
- }
-
- @Override
- public void starttls(ConnectionIn connection) {
- logger.debug("stream {} securing", connection.streamID);
- connection.sendStanza("<proceed xmlns=\"" + Connection.NS_TLS + "\" />");
- try {
- connection.setSocket(sc.getSocketFactory().createSocket(connection.getSocket(), connection.getSocket().getInetAddress().getHostAddress(),
- connection.getSocket().getPort(), false));
- SSLSocket sslSocket = (SSLSocket) connection.getSocket();
- sslSocket.addHandshakeCompletedListener(handshakeCompletedEvent -> {
- try {
- CertPath certPath = cf.generateCertPath(Arrays.asList(handshakeCompletedEvent.getPeerCertificates()));
- cpv.validate(certPath, params);
- connection.setTrusted(true);
- logger.info("connection from {} is trusted", connection.from);
- } catch (SSLPeerUnverifiedException | CertificateException | CertPathValidatorException | InvalidAlgorithmParameterException e) {
- logger.info("connection from {} is NOT trusted, falling back to dialback", connection.from);
- }
- });
- sslSocket.setUseClientMode(false);
- sslSocket.setNeedClientAuth(true);
- sslSocket.startHandshake();
- connection.setSecured(true);
- logger.debug("stream from {} secured", connection.streamID);
- connection.restartParser();
- } catch (XmlPullParserException | IOException sex) {
- logger.warn("stream {} ssl error {}", connection.streamID, sex);
- connection.sendStanza("<failure xmlns=\"" + Connection.NS_TLS + "\" />");
- removeConnectionIn(connection);
- connection.closeConnection();
- }
- }
-
- @Override
- public void proceed(ConnectionOut connection) {
- try {
- Socket socket = outConnections.get(connection).get();
- socket = sc.getSocketFactory().createSocket(socket, socket.getInetAddress().getHostAddress(),
- socket.getPort(), false);
- SSLSocket sslSocket = (SSLSocket) socket;
- sslSocket.addHandshakeCompletedListener(handshakeCompletedEvent -> {
- try {
- CertPath certPath = cf.generateCertPath(Arrays.asList(handshakeCompletedEvent.getPeerCertificates()));
- cpv.validate(certPath, params);
- connection.setTrusted(true);
- logger.info("connection to {} is trusted", connection.to);
- } catch (SSLPeerUnverifiedException | CertificateException | CertPathValidatorException | InvalidAlgorithmParameterException e) {
- logger.info("connection to {} is NOT trusted, falling back to dialback", connection.to);
- }
- });
- sslSocket.setNeedClientAuth(true);
- sslSocket.startHandshake();
- connection.setSecured(true);
- logger.debug("stream to {} secured", connection.getStreamID());
- connection.setInputStream(socket.getInputStream());
- connection.setOutputStream(socket.getOutputStream());
- connection.restartStream();
- connection.sendOpenStream();
- } catch (NoSuchElementException | XmlPullParserException | IOException sex) {
- logger.error("s2s ssl error: {} {}, error {}", connection.to, connection.getStreamID(), sex);
- connection.send("<failure xmlns=\"" + Connection.NS_TLS + "\" />");
- removeConnectionOut(connection);
- connection.logoff();
- }
- }
-
- @Override
- public void verify(ConnectionOut connection, String from, String type, String sid) {
- if (from != null && from.equals(connection.to.toEscapedString()) && sid != null && !sid.isEmpty() && type != null) {
- getConnectionIn(sid).ifPresent(c -> c.sendDialbackResult(Jid.of(from), type));
- }
- }
-
- @Override
- public void dialbackError(ConnectionOut connection, StreamError error) {
- logger.warn("Stream error from {}: {}", connection.getStreamID(), error.getCondition());
- removeConnectionOut(connection);
- connection.logoff();
- }
-
- @Override
- public void finished(ConnectionOut connection, boolean dirty) {
- logger.warn("stream to {} {} finished, dirty={}", connection.to, connection.getStreamID(), dirty);
- removeConnectionOut(connection);
- connection.logoff();
- }
-
- @Override
- public void exception(ConnectionOut connection, Exception ex) {
- logger.error("s2s out exception: {} {}, exception {}", connection.to, connection.getStreamID(), ex);
- removeConnectionOut(connection);
- connection.logoff();
- }
-
- @Override
- public void ready(ConnectionOut connection) {
- logger.debug("stream to {} {} ready", connection.to, connection.getStreamID());
- String cache = getFromCache(connection.to);
- if (cache != null) {
- logger.debug("stream to {} {} sending cache", connection.to, connection.getStreamID());
- connection.send(cache);
- }
- }
-
- @Override
- public boolean securing(ConnectionOut connection) {
- return tlsConfigured && !Arrays.asList(brokenSSLhosts).contains(connection.to.toEscapedString());
- }
-
- public Stanza parse(String xml) {
- try {
- Unmarshaller unmarshaller = session.createUnmarshaller();
- return (Stanza)unmarshaller.unmarshal(new StringReader(xml));
- } catch (JAXBException e) {
- logger.error("JAXB exception", e);
- }
- return null;
- }
-
- public Jid getJid() {
- return jid;
- }
- @Scheduled(fixedDelay = 10000)
- public void cleanUp() {
- Instant now = Instant.now();
- outConnections.keySet().stream().filter(c -> Duration.between(c.getUpdated(), now).toMinutes() > TIMEOUT_MINUTES)
- .forEach(c -> {
- logger.info("closing idle outgoing connection to {}", c.to);
- c.logoff();
- outConnections.remove(c);
- });
-
- inConnections.stream().filter(c -> Duration.between(c.updated, now).toMinutes() > TIMEOUT_MINUTES)
- .forEach(c -> {
- logger.info("closing idle incoming connection from {}", c.from);
- c.closeConnection();
- inConnections.remove(c);
- });
- }
- @PreDestroy
- public void preDestroy() throws IOException {
- closeFlag.set(true);
- if (listener != null && !listener.isClosed()) {
- listener.close();
- }
- service.shutdown();
- logger.info("XMPP server destroyed");
- }
-
- public int getServerPort() {
- return s2sPort;
- }
-}
diff --git a/src/main/java/com/juick/server/api/ApiSocialLogin.java b/src/main/java/com/juick/server/api/ApiSocialLogin.java
index 72cda0af..be306fe9 100644
--- a/src/main/java/com/juick/server/api/ApiSocialLogin.java
+++ b/src/main/java/com/juick/server/api/ApiSocialLogin.java
@@ -82,6 +82,7 @@ public class ApiSocialLogin {
@Inject
private ObjectMapper jsonMapper;
private ServiceBuilder facebookBuilder, twitterBuilder, vkBuilder;
+ private OAuth20Service facebookAuthService, vkAuthService;
@Value("${twitter_consumer_key:appid}")
private String twitterConsumerKey;
@@ -117,6 +118,16 @@ public class ApiSocialLogin {
verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
.setAudience(Collections.singletonList(googleClientId))
.build();
+ facebookAuthService = facebookBuilder
+ .apiSecret(FACEBOOK_SECRET)
+ .callback(FACEBOOK_REDIRECT)
+ .scope("email")
+ .build(FacebookApi.instance());
+ vkAuthService = vkBuilder
+ .apiSecret(VK_SECRET)
+ .scope("friends,wall,offline")
+ .callback(VK_REDIRECT)
+ .build(VkontakteApi.instance());
}
@GetMapping("/api/_fblogin")
@@ -125,13 +136,7 @@ public class ApiSocialLogin {
if (StringUtils.isBlank(code)) {
String fbstate = UUID.randomUUID().toString();
crosspostService.addFacebookState(fbstate, state);
- OAuth20Service facebookAuthService = facebookBuilder
- .apiSecret(FACEBOOK_SECRET)
- .callback(FACEBOOK_REDIRECT)
- .scope("email")
- .state(fbstate)
- .build(FacebookApi.instance());
- return "redirect:" + facebookAuthService.getAuthorizationUrl();
+ return "redirect:" + facebookAuthService.getAuthorizationUrl(fbstate);
}
String redirectUrl = crosspostService.verifyFacebookState(state);
@@ -140,53 +145,43 @@ public class ApiSocialLogin {
logger.error("state is missing");
throw new HttpBadRequestException();
}
- OAuth20Service facebookService = facebookBuilder
- .apiKey(FACEBOOK_APPID)
- .apiSecret(FACEBOOK_SECRET)
- .callback(FACEBOOK_REDIRECT)
- .scope("email")
- .state(state)
- .build(FacebookApi.instance());
- OAuth2AccessToken token = facebookService.getAccessToken(code);
- final OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://graph.facebook.com/v2.10/me?fields=id,name,link,verified,email");
- facebookService.signRequest(token, meRequest);
- String graph = facebookService.execute(meRequest).getBody();
+ OAuth2AccessToken token = facebookAuthService.getAccessToken(code);
+ final OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://graph.facebook.com/v3.2/me?fields=id,name,email");
+ facebookAuthService.signRequest(token, meRequest);
+ String graph = facebookAuthService.execute(meRequest).getBody();
if (StringUtils.isBlank(graph)) {
logger.error("FACEBOOK GRAPH ERROR");
throw new HttpBadRequestException();
}
User fb = jsonMapper.readValue(graph, User.class);
long fbID = NumberUtils.toLong(fb.getId(), 0);
- if (fbID == 0 || StringUtils.isBlank(fb.getName()) || StringUtils.isBlank(fb.getLink())) {
- logger.error("Missing required fields, id: {}, name: {}, link: {}", fbID, fb.getName(), fb.getLink());
+ if (fbID == 0 || StringUtils.isBlank(fb.getName())) {
+ logger.error("Missing required fields, id: {}, name: {}", fbID, fb.getName());
throw new HttpBadRequestException();
}
int uid = crosspostService.getUIDbyFBID(fbID);
if (uid > 0) {
- if (!crosspostService.updateFacebookUser(fbID, token.getAccessToken(), fb.getName(), fb.getLink())) {
+ if (!crosspostService.updateFacebookUser(fbID, token.getAccessToken(), fb.getName())) {
logger.error("error updating facebook user, id: {}, token: {}", fbID, token.getAccessToken());
throw new HttpBadRequestException();
}
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(redirectUrl);
uriComponentsBuilder.queryParam("hash", userService.getHashByUID(uid));
return "redirect:" + uriComponentsBuilder.build().toUriString();
- } else if (fb.getVerified()) {
- if (!crosspostService.createFacebookUser(fbID, state, token.getAccessToken(), fb.getName(), fb.getLink())) {
+ } else {
+ if (!crosspostService.createFacebookUser(fbID, state, token.getAccessToken(), fb.getName())) {
if (StringUtils.isNotEmpty(fb.getEmail())) {
- logger.info("found {} for facebook user {}", fb.getEmail(), fb.getLink());
+ logger.info("found {} for facebook user {}", fb.getEmail());
Integer userId = crosspostService.getUIDbyFBID(fbID);
if (!emailService.getEmails(userId, false).contains(fb.getEmail())) {
emailService.addEmail(userId, fb.getEmail());
}
}
- logger.info("email not found for facebook user {}", fb.getLink());
+ logger.info("email not found for facebook user {}", fb.getName());
throw new HttpBadRequestException();
}
return "redirect:/signup?type=fb&hash=" + state;
- } else {
- logger.error("Facebook account is not verified, id: {}", fbID);
- throw new HttpBadRequestException();
}
}/*
@GetMapping("/_twitter")
@@ -244,13 +239,7 @@ public class ApiSocialLogin {
if (StringUtils.isBlank(code)) {
String vkstate = UUID.randomUUID().toString();
crosspostService.addVKState(vkstate, state);
- OAuth20Service vkAuthService = vkBuilder
- .apiSecret(VK_SECRET)
- .scope("friends,wall,offline")
- .state(vkstate)
- .callback(VK_REDIRECT)
- .build(VkontakteApi.instance());
- return "redirect:" + vkAuthService.getAuthorizationUrl();
+ return "redirect:" + vkAuthService.getAuthorizationUrl(vkstate);
}
String redirectUrl = crosspostService.verifyVKState(state);
@@ -258,16 +247,11 @@ public class ApiSocialLogin {
logger.error("state is missing");
throw new HttpBadRequestException();
}
-
- OAuth20Service vkService = vkBuilder
- .apiKey(VK_APPID)
- .apiSecret(VK_SECRET)
- .build(VkontakteApi.instance());
- OAuth2AccessToken token = vkService.getAccessToken(code);
+ OAuth2AccessToken token = vkAuthService.getAccessToken(code);
OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://api.vk.com/method/users.get?fields=screen_name&v=5.73");
- vkService.signRequest(token, meRequest);
- String graph = vkService.execute(meRequest).getBody();
+ vkAuthService.signRequest(token, meRequest);
+ String graph = vkAuthService.execute(meRequest).getBody();
com.juick.model.vk.User jsonUser = jsonMapper.readValue(graph, UsersResponse.class).getUsers().get(0);
String vkName = jsonUser.getFirstName() + " " + jsonUser.getLastName();
diff --git a/src/main/java/com/juick/server/api/Index.java b/src/main/java/com/juick/server/api/Index.java
index 56f01370..4573641b 100644
--- a/src/main/java/com/juick/server/api/Index.java
+++ b/src/main/java/com/juick/server/api/Index.java
@@ -17,10 +17,7 @@
package com.juick.server.api;
-import com.juick.Status;
-import com.juick.server.WebsocketManager;
import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -28,7 +25,6 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import springfox.documentation.annotations.ApiIgnore;
-import javax.inject.Inject;
import java.net.URI;
/**
@@ -36,19 +32,11 @@ import java.net.URI;
*/
@RestController
public class Index {
- @Inject
- private WebsocketManager wsHandler;
@ApiIgnore
- @RequestMapping(value = { "/api/", "/ws/" }, method = RequestMethod.GET, headers = "Connection!=Upgrade")
+ @RequestMapping(value = { "/api/", "/ws/" }, method = RequestMethod.GET)
public ResponseEntity<Void> description() {
URI redirectUri = ServletUriComponentsBuilder.fromCurrentRequestUri().path("/swagger-ui.html").build().toUri();
return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY).location(redirectUri).build();
}
- @ApiIgnore
- @RequestMapping(value = "/api/status", method = RequestMethod.GET,
- produces = MediaType.APPLICATION_JSON_UTF8_VALUE, headers = "Connection!=Upgrade")
- public Status status() {
- return Status.getStatus(String.valueOf(wsHandler.getClients().size()));
- }
}
diff --git a/src/main/java/com/juick/server/api/Messages.java b/src/main/java/com/juick/server/api/Messages.java
index e105890f..5c791df4 100644
--- a/src/main/java/com/juick/server/api/Messages.java
+++ b/src/main/java/com/juick/server/api/Messages.java
@@ -179,6 +179,9 @@ public class Messages {
}
msg.getUser().setAvatar(webApp.getAvatarUrl(msg.getUser()));
msg.setRecommendations(new HashSet<>(messagesService.getMessageRecommendations(msg.getMid())));
+ msg.getRecommendations().forEach(r -> {
+ r.setAvatar(webApp.getAvatarUrl(r));
+ });
List<com.juick.Message> replies = messagesService.getReplies(visitor, mid);
replies.forEach(m -> m.getUser().setAvatar(webApp.getAvatarUrl(m.getUser())));
if (!visitor.isAnonymous()) {
diff --git a/src/main/java/com/juick/server/api/Notifications.java b/src/main/java/com/juick/server/api/Notifications.java
index 000a9f3b..ea1d5c54 100644
--- a/src/main/java/com/juick/server/api/Notifications.java
+++ b/src/main/java/com/juick/server/api/Notifications.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2017, Juick
+ * Copyright (C) 2008-2019, Juick
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -24,14 +24,19 @@ import com.juick.User;
import com.juick.model.AnonymousUser;
import com.juick.server.util.HttpBadRequestException;
import com.juick.server.util.HttpForbiddenException;
+import com.juick.server.util.UserUtils;
import com.juick.service.MessagesService;
import com.juick.service.PushQueriesService;
import com.juick.service.SubscriptionService;
-import com.juick.server.util.UserUtils;
+import com.juick.service.TelegramService;
import com.juick.service.UserService;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;
import javax.inject.Inject;
@@ -55,6 +60,8 @@ public class Notifications {
private SubscriptionService subscriptionService;
@Inject
private UserService userService;
+ @Inject
+ private TelegramService telegramService;
private User collectTokens(Integer uid) {
@@ -63,6 +70,14 @@ public class Notifications {
pushQueriesService.getGCMRegID(uid).forEach(t -> user.getTokens().add(new ExternalToken(null, "gcm", t, null)));
pushQueriesService.getAPNSToken(uid).forEach(t -> user.getTokens().add(new ExternalToken(null, "apns", t, null)));
pushQueriesService.getMPNSURL(uid).forEach(t -> user.getTokens().add(new ExternalToken(null, "mpns", t, null)));
+ List<ExternalToken> xmppJids = userService.getJIDsbyUID(uid).stream()
+ .map(jid -> new ExternalToken(null, "xmpp", jid, null))
+ .collect(Collectors.toList());
+ user.getTokens().addAll(xmppJids);
+ List<ExternalToken> tgIds = telegramService.getTelegramIdentifiers(Collections.singletonList(user)).stream()
+ .map(tgId -> new ExternalToken(null, "durov", String.valueOf(tgId), null))
+ .collect(Collectors.toList());
+ user.getTokens().addAll(tgIds);
return user;
}
diff --git a/src/main/java/com/juick/server/api/PM.java b/src/main/java/com/juick/server/api/PM.java
index a80ad0dc..e61fef6e 100644
--- a/src/main/java/com/juick/server/api/PM.java
+++ b/src/main/java/com/juick/server/api/PM.java
@@ -99,6 +99,7 @@ public class PM {
jmsg.setUser(visitor);
jmsg.setText(body);
jmsg.setTo(userTo);
+ jmsg.getUser().setAvatar(webApp.getAvatarUrl(jmsg.getUser()));
applicationEventPublisher.publishEvent(new MessageEvent(this, jmsg, Collections.singletonList(jmsg.getTo())));
return jmsg;
diff --git a/src/main/java/com/juick/server/api/Users.java b/src/main/java/com/juick/server/api/Users.java
index 6f9ab290..33b3704b 100644
--- a/src/main/java/com/juick/server/api/Users.java
+++ b/src/main/java/com/juick/server/api/Users.java
@@ -18,21 +18,24 @@
package com.juick.server.api;
import com.juick.User;
+import com.juick.model.AnonymousUser;
import com.juick.model.ApplicationStatus;
-import com.juick.model.UserInfo;
-import com.juick.server.util.HttpForbiddenException;
import com.juick.server.util.HttpNotFoundException;
-import com.juick.server.www.WebApp;
-import com.juick.service.CrosspostService;
-import com.juick.service.EmailService;
-import com.juick.service.MessagesService;
-import com.juick.service.UserService;
+import com.juick.server.util.HttpUtils;
import com.juick.server.util.UserUtils;
import com.juick.server.util.WebUtils;
+import com.juick.server.www.WebApp;
+import com.juick.service.*;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
import javax.inject.Inject;
+import java.io.IOException;
+import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -52,6 +55,10 @@ public class Users {
private EmailService emailService;
@Inject
private WebApp webApp;
+ @Inject
+ private ImagesService imagesService;
+ @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
+ private String tmpDir;
@RequestMapping(value = "/api/auth", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String getAuthToken() {
@@ -94,16 +101,21 @@ public class Users {
me.setRead(userService.getUserFriends(visitor.getUid()));
me.setReaders(userService.getUserReaders(visitor.getUid()));
me.setAvatar(webApp.getAvatarUrl(visitor));
- return me;
+ return (SecureUser)userService.getUserInfo(me);
+ }
+ @PostMapping("/api/me/upload")
+ public void updateInfo(@RequestParam MultipartFile avatar) throws IOException {
+ User visitor = UserUtils.getCurrentUser();
+ String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, tmpDir).getHost();
+ if (StringUtils.isNotEmpty(avatarTmpPath)) {
+ imagesService.saveAvatar(avatarTmpPath, visitor.getUid());
+ }
}
@RequestMapping(value = "/api/users/read", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public List<User> doGetUserRead(
@RequestParam String uname) {
User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpForbiddenException();
- }
int uid = 0;
if (uname == null) {
uid = visitor.getUid();
@@ -128,9 +140,6 @@ public class Users {
public List<User> doGetUserReaders(
@RequestParam String uname) {
User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpForbiddenException();
- }
int uid = 0;
if (uname == null) {
uid = visitor.getUid();
@@ -152,22 +161,36 @@ public class Users {
}
@GetMapping("/api/info/{uname}")
- public UserInfo getUserInfo(@PathVariable String uname) {
+ public User getUserInfo(@PathVariable String uname) {
User user = userService.getUserByName(uname);
if (!user.isBanned()) {
+ user.setRead(doGetUserRead(uname));
+ user.setReaders(doGetUserReaders(uname));
user.setAvatar(webApp.getAvatarUrl(user));
return userService.getUserInfo(user);
}
throw new HttpNotFoundException();
}
+ @Deprecated
+ @GetMapping(value = "/api/avatar", produces = MediaType.IMAGE_PNG_VALUE)
+ public byte[] getAvatarUrl(
+ @RequestParam(required = false) String uname,
+ @RequestParam(required = false) String jid)
+ throws IOException {
+ User user = AnonymousUser.INSTANCE;
+ if (StringUtils.isNotEmpty(uname)) {
+ user = userService.getUserByName(uname);
+ }
+ if (user.isAnonymous() && StringUtils.isNotEmpty(jid)) {
+ user = userService.getUserByJID(jid);
+ }
+ return IOUtils.toByteArray(URI.create(webApp.getAvatarUrl(user)));
+ }
class SecureUser extends User {
public String getHash() {
return getAuthHash();
}
- public UserInfo getUserInfo() {
- return userService.getUserInfo(this);
- }
public List<String> getJIDs() {
return userService.getAllJIDs(this);
}
diff --git a/src/main/java/com/juick/server/api/activity/Profile.java b/src/main/java/com/juick/server/api/activity/Profile.java
index 305b7c4a..4e375a54 100644
--- a/src/main/java/com/juick/server/api/activity/Profile.java
+++ b/src/main/java/com/juick/server/api/activity/Profile.java
@@ -3,6 +3,7 @@ package com.juick.server.api.activity;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.juick.Message;
import com.juick.User;
+import com.juick.formatters.PlainTextFormatter;
import com.juick.model.CommandResult;
import com.juick.server.ActivityPubManager;
import com.juick.server.CommandsManager;
@@ -29,6 +30,8 @@ import com.juick.server.www.WebApp;
import com.juick.service.MessagesService;
import com.juick.service.UserService;
import com.juick.service.activities.*;
+import com.overzealous.remark.Remark;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,12 +47,15 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import javax.inject.Inject;
+import java.io.InputStream;
import java.net.URI;
+import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -81,6 +87,8 @@ public class Profile {
private ObjectMapper jsonMapper;
@Inject
private WebApp webApp;
+ @Inject
+ private Remark remarkConverter;
@GetMapping(value = "/u/{userName}", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE})
public Person getUser(@PathVariable String userName) {
@@ -252,32 +260,17 @@ public class Profile {
}
@PostMapping(value = "/api/inbox", consumes = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE})
- public ResponseEntity<Void> processInbox(@RequestBody Activity activity,
- @RequestHeader(name = "Host") String host,
- @RequestHeader(name = "Date") String date,
- @RequestHeader(name = "Digest", required = false) String digest,
- @RequestHeader(name = "Content-Type") String contentType,
- @RequestHeader(name = "User-Agent", required = false) String userAgent,
- @RequestHeader(name = "Accept-Encoding", required = false) String acceptEncoding,
- @RequestHeader(name = "Signature", required = false) String signature) throws Exception {
- UriComponents componentsBuilder = ServletUriComponentsBuilder.fromCurrentRequestUri().build();
- Map<String, String> headers = new HashMap<>();
- headers.put("host", host.split(":", 2)[0]);
- headers.put("date", date);
- headers.put("digest", digest);
- headers.put("content-type", contentType);
- headers.put("user-agent", userAgent);
- headers.put("accept-encoding", acceptEncoding);
- boolean valid = signatureManager.verifySignature(signature, URI.create(activity.getActor()), "POST",
- componentsBuilder.getPath(), headers);
- if (valid) {
+ public ResponseEntity<CommandResult> processInbox(InputStream inboxData) throws Exception {
+ String inbox = IOUtils.toString(inboxData, StandardCharsets.UTF_8);
+ logger.info("Inbox: {}", inbox);
+ Activity activity = jsonMapper.readValue(inbox, Activity.class);
+ User visitor = UserUtils.getCurrentUser();
+ if ((StringUtils.isNotEmpty(visitor.getUri().toString()) && visitor.getUri().equals(URI.create(activity.getActor()))) || !visitor.isAnonymous()) {
if (activity instanceof Follow) {
Follow followRequest = (Follow) activity;
- String actor = followRequest.getActor();
- Person follower = (Person) signatureManager.getContext(URI.create(actor)).orElseThrow(HttpBadRequestException::new);
applicationEventPublisher.publishEvent(
new FollowEvent(this, followRequest));
- return new ResponseEntity<>(HttpStatus.ACCEPTED);
+ return new ResponseEntity<>(CommandResult.fromString("Follow request accepted"), HttpStatus.ACCEPTED);
}
if (activity instanceof Undo) {
@@ -286,17 +279,10 @@ public class Profile {
String objectObject = (String) object.get("object");
if (objectType.equals("Follow")) {
applicationEventPublisher.publishEvent(new UndoFollowEvent(this, activity.getActor(), objectObject));
- return new ResponseEntity<>(HttpStatus.OK);
+ return new ResponseEntity<>(CommandResult.fromString("Undo follow request accepted"), HttpStatus.OK);
} else if (objectType.equals("Like") || objectType.equals("Announce")) {
applicationEventPublisher.publishEvent(new UndoAnnounceEvent(this, activity.getActor(), objectObject));
- return new ResponseEntity<>(HttpStatus.OK);
- }
- }
- if (activity instanceof Delete) {
- if (activity.getObject() instanceof String) {
- // Delete user
- applicationEventPublisher.publishEvent(new DeleteUserEvent(this, (String)activity.getObject()));
- return new ResponseEntity<>(HttpStatus.OK);
+ return new ResponseEntity<>(CommandResult.fromString("Undo like/announce request accepted"), HttpStatus.OK);
}
}
if (activity instanceof Create) {
@@ -305,7 +291,7 @@ public class Profile {
if (note.get("type").equals("Note")) {
URI noteId = URI.create((String) note.get("id"));
if (messagesService.replyExists(noteId)) {
- return new ResponseEntity<>(HttpStatus.OK);
+ return new ResponseEntity<>(CommandResult.fromString("Reply already exists"), HttpStatus.OK);
} else {
String inReplyTo = (String) note.get("inReplyTo");
if (StringUtils.isNotBlank(inReplyTo)) {
@@ -313,36 +299,50 @@ public class Profile {
String postId = activityPubManager.postId(inReplyTo);
User user = new User();
user.setUri(URI.create(activity.getActor()));
- String attachment = StringUtils.EMPTY;
- if (note.get("attachment") != null && ((List) note.get("attachment")).size() > 0) {
- Map<String, Object> attachmentObj = (Map<String, Object>) ((List<Object>) note.get("attachment")).get(0);
- attachment = (String) attachmentObj.get("url");
- }
- CommandResult result = commandsManager.processCommand(user, String.format("#%s %s", postId, note.get("content")), URI.create(attachment));
+ String markdown = remarkConverter.convertFragment((String) note.get("content"));
+ String commandBody = note.get("attachment") == null ? markdown :
+ ((List<Object>) note.get("attachment")).stream().map(attachmentObj -> {
+ Map<String, String> attachment = (Map<String, String>) attachmentObj;
+ String attachmentUrl = attachment.get("url");
+ String attachmentName = attachment.get("name");
+ return PlainTextFormatter.markdownUrl(attachmentUrl, attachmentName);
+ }).reduce((source, url) -> String.format("%s\n%s", source, url))
+ .orElse(markdown);
+
+ CommandResult result = commandsManager.processCommand(
+ user, String.format("#%s %s", postId, commandBody),
+ URI.create(StringUtils.EMPTY));
logger.info(jsonMapper.writeValueAsString(result));
if (result.getNewMessage().isPresent()) {
messagesService.updateReplyUri(result.getNewMessage().get(), noteId);
- return new ResponseEntity<>(HttpStatus.OK);
+ return new ResponseEntity<>(result, HttpStatus.OK);
} else {
- return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
+ return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
}
} else {
Message reply = messagesService.getReplyByUri(inReplyTo);
if (reply != null) {
User user = new User();
user.setUri(URI.create(activity.getActor()));
- String attachment = StringUtils.EMPTY;
- if (note.get("attachment") != null && ((List) note.get("attachment")).size() > 0) {
- Map<String, Object> attachmentObj = (Map<String, Object>) ((List<Object>) note.get("attachment")).get(0);
- attachment = (String) attachmentObj.get("url");
- }
- CommandResult result = commandsManager.processCommand(user, String.format("#%d/%d %s", reply.getMid(), reply.getRid(), note.get("content")), URI.create(attachment));
+ String markdown = remarkConverter.convertFragment((String)note.get("content"));
+ String commandBody = note.get("attachment") == null ? markdown :
+ ((List<Object>) note.get("attachment")).stream().map(attachmentObj -> {
+ Map<String, String> attachment = (Map<String, String>) attachmentObj;
+ String attachmentUrl = attachment.get("url");
+ String attachmentName = attachment.get("name");
+ return PlainTextFormatter.markdownUrl(attachmentUrl, attachmentName);
+ }).reduce((source, url) -> String.format("%s\n%s", source, url))
+ .orElse(markdown);
+ CommandResult result = commandsManager.processCommand(
+ user,
+ String.format("#%d/%d %s", reply.getMid(), reply.getRid(), commandBody),
+ URI.create(StringUtils.EMPTY));
logger.info(jsonMapper.writeValueAsString(result));
if (result.getNewMessage().isPresent()) {
messagesService.updateReplyUri(result.getNewMessage().get(), noteId);
- return new ResponseEntity<>(HttpStatus.OK);
+ return new ResponseEntity<>(result, HttpStatus.OK);
} else {
- return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
+ return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
}
}
}
@@ -357,17 +357,28 @@ public class Profile {
URI actor = URI.create(activity.getActor());
URI reply = URI.create((String)tombstone.get("id"));
messagesService.deleteReply(actor, reply);
- return new ResponseEntity<>(HttpStatus.OK);
+ return new ResponseEntity<>(CommandResult.fromString("Delete request accepted"), HttpStatus.OK);
}
}
if (activity instanceof Like || activity instanceof Announce) {
- applicationEventPublisher.publishEvent(new AnnounceEvent(this, activity.getActor(), (String)activity.getObject()));
- return new ResponseEntity<>(HttpStatus.OK);
+ String messageUri = activity.getObject() instanceof String ? (String) activity.getObject()
+ : activity.getObject() instanceof Context ? ((Context) activity.getObject()).getId()
+ : (String) ((Map)activity.getObject()).get("id");
+ applicationEventPublisher.publishEvent(new AnnounceEvent(this, activity.getActor(), messageUri));
+ return new ResponseEntity<>(CommandResult.fromString("Like/announce request accepted"), HttpStatus.OK);
}
logger.warn("Unknown activity: {}", jsonMapper.writeValueAsString(activity));
- return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
+ return new ResponseEntity<>(CommandResult.fromString("Unknown activity"), HttpStatus.NOT_IMPLEMENTED);
+ }
+ if (activity instanceof Delete) {
+ if (activity.getObject() instanceof String) {
+ // Delete gone user
+ if (activity.getActor().equals(activity.getObject())) {
+ return new ResponseEntity<>(CommandResult.fromString("Delete request accepted"), HttpStatus.ACCEPTED);
+ }
+ }
}
- return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
+ return new ResponseEntity<>(CommandResult.fromString("Can not authenticate"), HttpStatus.UNAUTHORIZED);
}
@PostMapping(value = "/u/", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public User fetchUser(@RequestParam URI uri) {
diff --git a/src/main/java/com/juick/server/api/activity/helpers/ActivityIdDeserializer.java b/src/main/java/com/juick/server/api/activity/helpers/ActivityIdDeserializer.java
new file mode 100644
index 00000000..ba8cfb87
--- /dev/null
+++ b/src/main/java/com/juick/server/api/activity/helpers/ActivityIdDeserializer.java
@@ -0,0 +1,22 @@
+package com.juick.server.api.activity.helpers;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.io.IOException;
+
+public class ActivityIdDeserializer extends JsonDeserializer<String> {
+ @Override
+ public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ JsonToken jsonToken = p.getCurrentToken();
+ if (jsonToken == JsonToken.START_OBJECT) {
+ JsonNode node = p.getCodec().readTree(p);
+ return node.get("id").textValue();
+ }
+ return p.getValueAsString();
+ }
+}
diff --git a/src/main/java/com/juick/server/api/activity/helpers/LinkValueDeserializer.java b/src/main/java/com/juick/server/api/activity/helpers/LinkValueDeserializer.java
new file mode 100644
index 00000000..a635ea95
--- /dev/null
+++ b/src/main/java/com/juick/server/api/activity/helpers/LinkValueDeserializer.java
@@ -0,0 +1,21 @@
+package com.juick.server.api.activity.helpers;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.io.IOException;
+
+public class LinkValueDeserializer extends JsonDeserializer<String> {
+ @Override
+ public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+ JsonToken jsonToken = p.getCurrentToken();
+ if (jsonToken == JsonToken.VALUE_STRING) {
+ return p.getValueAsString();
+ }
+ JsonNode node = p.getCodec().readTree(p);
+ return node.get("href").textValue();
+ }
+}
diff --git a/src/main/java/com/juick/server/api/activity/model/Activity.java b/src/main/java/com/juick/server/api/activity/model/Activity.java
index ec126b88..2af14479 100644
--- a/src/main/java/com/juick/server/api/activity/model/Activity.java
+++ b/src/main/java/com/juick/server/api/activity/model/Activity.java
@@ -1,7 +1,11 @@
package com.juick.server.api.activity.model;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.juick.server.api.activity.helpers.ActivityIdDeserializer;
+
public abstract class Activity extends Context {
+ @JsonDeserialize(using = ActivityIdDeserializer.class)
private String actor;
private Object object;
diff --git a/src/main/java/com/juick/server/api/activity/model/Context.java b/src/main/java/com/juick/server/api/activity/model/Context.java
index 515ee3da..2ba4606e 100644
--- a/src/main/java/com/juick/server/api/activity/model/Context.java
+++ b/src/main/java/com/juick/server/api/activity/model/Context.java
@@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.juick.server.api.activity.helpers.LinkValueDeserializer;
import com.juick.server.api.activity.model.activities.*;
import com.juick.server.api.activity.model.objects.*;
@@ -46,6 +48,7 @@ public abstract class Context {
private Instant published;
+ @JsonDeserialize(using = LinkValueDeserializer.class)
private String url;
private List<String> to;
diff --git a/src/main/java/com/juick/server/api/rss/MessagesView.java b/src/main/java/com/juick/server/api/rss/MessagesView.java
index 05bc0bd6..2c05c8cb 100644
--- a/src/main/java/com/juick/server/api/rss/MessagesView.java
+++ b/src/main/java/com/juick/server/api/rss/MessagesView.java
@@ -126,7 +126,7 @@ public class MessagesView extends AbstractRssFeedView {
description.setType("text/html");
description.setValue(messageDescription);
item.setDescription(description);
- item.setPubDate(Date.from(msg.getTimestamp()));
+ item.setPubDate(Date.from(msg.getCreated()));
item.setComments(messageUrl);
msg.getTags().stream().map(t -> {
Category category = new Category();
diff --git a/src/main/java/com/juick/server/api/webfinger/Resource.java b/src/main/java/com/juick/server/api/webfinger/Resource.java
index 71a0ca31..4e0447f7 100644
--- a/src/main/java/com/juick/server/api/webfinger/Resource.java
+++ b/src/main/java/com/juick/server/api/webfinger/Resource.java
@@ -26,7 +26,7 @@ public class Resource {
@Value("${ap_base_uri:http://localhost:8080/}")
private String baseUri;
- @GetMapping("/.well-known/webfinger")
+ @GetMapping(value = "/.well-known/webfinger", produces = "application/jrd+json;charset=utf-8")
public Account getWebResource(@RequestParam String resource) {
if (resource.startsWith("acct:")) {
Jid account = Jid.of(resource.substring(5));
diff --git a/src/main/java/com/juick/server/api/xnodeinfo2/Info.java b/src/main/java/com/juick/server/api/xnodeinfo2/Info.java
index 36e36bdd..493bff6a 100644
--- a/src/main/java/com/juick/server/api/xnodeinfo2/Info.java
+++ b/src/main/java/com/juick/server/api/xnodeinfo2/Info.java
@@ -1,15 +1,24 @@
package com.juick.server.api.xnodeinfo2;
+import com.cliqset.xrd.Link;
+import com.cliqset.xrd.XRD;
+import com.fasterxml.jackson.annotation.JsonView;
import com.juick.server.api.xnodeinfo2.model.*;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.MediaType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.util.UriComponentsBuilder;
import javax.inject.Inject;
+import java.net.URI;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
@RestController
public class Info {
@@ -18,9 +27,9 @@ public class Info {
@Inject
private JdbcTemplate jdbcTemplate;
- @GetMapping("/.well-known/x-nodeinfo2")
- public NodeInfo showNodeInfo() {
+ private NodeInfo getCurrentNodeInfo(String version) {
NodeInfo nodeInfo = new NodeInfo();
+ nodeInfo.setVersion(version);
Server server = new Server();
server.setBaseUrl(baseUri);
server.setName("Juick");
@@ -28,6 +37,9 @@ public class Info {
server.setVersion("2.x");
nodeInfo.setServer(server);
nodeInfo.setProtocols(Arrays.asList("xmpp", "activitypub", "smtp"));
+ Map<String, String> metadata = new HashMap<>();
+ metadata.put("email", "support@juick.com");
+ nodeInfo.setMetadata(metadata);
ServiceInfo serviceInfo = new ServiceInfo();
serviceInfo.setInbound(Arrays.asList("jabber", "mastodon", "email", "telegram"));
serviceInfo.setOutbound(Arrays.asList("jabber", "mastodon", "telegram", "twitter", "email", "rss"));
@@ -47,4 +59,28 @@ public class Info {
nodeInfo.setUsage(usage);
return nodeInfo;
}
+
+ @GetMapping(value = "/.well-known/x-nodeinfo2", produces = MediaType.APPLICATION_JSON_VALUE)
+ @JsonView(NodeInfo.XNodeInfoView.class)
+ public NodeInfo showXNodeInfo() {
+ return getCurrentNodeInfo("1.0");
+ }
+
+ @GetMapping(value = "/.well-known/nodeinfo", produces = MediaType.APPLICATION_JSON_VALUE)
+ public XRD getNodeInfoLinks() {
+ Link nodeinfo = new Link();
+ nodeinfo.setRel(URI.create("http://nodeinfo.diaspora.software/ns/schema/2.0"));
+ UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUri);
+ uriComponentsBuilder.replacePath("/api/nodeinfo/2.0");
+ nodeinfo.setHref(uriComponentsBuilder.build().toUri());
+ XRD xrd = new XRD();
+ xrd.setLinks(Collections.singletonList(nodeinfo));
+ return xrd;
+ }
+
+ @GetMapping(value = "/api/nodeinfo/2.0", produces = MediaType.APPLICATION_JSON_VALUE)
+ @JsonView(NodeInfo.NodeInfoView.class)
+ public NodeInfo showNodeInfo() {
+ return getCurrentNodeInfo("2.0");
+ }
}
diff --git a/src/main/java/com/juick/server/api/xnodeinfo2/model/NodeInfo.java b/src/main/java/com/juick/server/api/xnodeinfo2/model/NodeInfo.java
index 06fe354f..1ebe39a8 100644
--- a/src/main/java/com/juick/server/api/xnodeinfo2/model/NodeInfo.java
+++ b/src/main/java/com/juick/server/api/xnodeinfo2/model/NodeInfo.java
@@ -1,27 +1,45 @@
package com.juick.server.api.xnodeinfo2.model;
+import com.fasterxml.jackson.annotation.JsonView;
+
import java.util.List;
+import java.util.Map;
public class NodeInfo {
+ private String version;
+
private Server server;
private List<String> protocols;
private ServiceInfo services;
+ private Map<String, String> metadata;
+
+ @JsonView({XNodeInfoView.class, NodeInfoView.class})
public String getVersion() {
- return "1.0";
+ return version;
}
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ @JsonView(XNodeInfoView.class)
public Server getServer() {
return server;
}
+ @JsonView(NodeInfoView.class)
+ public Server getSoftware() {
+ return server;
+ }
public void setServer(Server server) {
this.server = server;
}
+ @JsonView({XNodeInfoView.class, NodeInfoView.class})
public List<String> getProtocols() {
return protocols;
}
@@ -30,6 +48,7 @@ public class NodeInfo {
this.protocols = protocols;
}
+ @JsonView({XNodeInfoView.class, NodeInfoView.class})
public ServiceInfo getServices() {
return services;
}
@@ -38,12 +57,14 @@ public class NodeInfo {
this.services = services;
}
+ @JsonView({XNodeInfoView.class, NodeInfoView.class})
public boolean getOpenRegistrations() {
return true;
}
private Usage usage;
+ @JsonView({XNodeInfoView.class, NodeInfoView.class})
public Usage getUsage() {
return usage;
}
@@ -51,4 +72,16 @@ public class NodeInfo {
public void setUsage(Usage usage) {
this.usage = usage;
}
+
+ @JsonView(NodeInfoView.class)
+ public Map<String, String> getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(Map<String, String> metadata) {
+ this.metadata = metadata;
+ }
+
+ public interface NodeInfoView {}
+ public interface XNodeInfoView {}
}
diff --git a/src/main/java/com/juick/server/api/xnodeinfo2/model/Server.java b/src/main/java/com/juick/server/api/xnodeinfo2/model/Server.java
index a772d268..08c1a696 100644
--- a/src/main/java/com/juick/server/api/xnodeinfo2/model/Server.java
+++ b/src/main/java/com/juick/server/api/xnodeinfo2/model/Server.java
@@ -1,11 +1,14 @@
package com.juick.server.api.xnodeinfo2.model;
+import com.fasterxml.jackson.annotation.JsonView;
+
public class Server {
private String baseUrl;
private String name;
private String software;
private String version;
+ @JsonView(NodeInfo.XNodeInfoView.class)
public String getBaseUrl() {
return baseUrl;
}
@@ -14,6 +17,7 @@ public class Server {
this.baseUrl = baseUrl;
}
+ @JsonView({NodeInfo.NodeInfoView.class, NodeInfo.XNodeInfoView.class})
public String getName() {
return name;
}
@@ -22,6 +26,7 @@ public class Server {
this.name = name;
}
+ @JsonView(NodeInfo.XNodeInfoView.class)
public String getSoftware() {
return software;
}
@@ -30,6 +35,7 @@ public class Server {
this.software = software;
}
+ @JsonView({NodeInfo.NodeInfoView.class, NodeInfo.XNodeInfoView.class})
public String getVersion() {
return version;
}
diff --git a/src/main/java/com/juick/server/api/xnodeinfo2/model/ServiceInfo.java b/src/main/java/com/juick/server/api/xnodeinfo2/model/ServiceInfo.java
index 5b6d2baa..0114488f 100644
--- a/src/main/java/com/juick/server/api/xnodeinfo2/model/ServiceInfo.java
+++ b/src/main/java/com/juick/server/api/xnodeinfo2/model/ServiceInfo.java
@@ -1,7 +1,10 @@
package com.juick.server.api.xnodeinfo2.model;
+import com.fasterxml.jackson.annotation.JsonView;
+
import java.util.List;
+@JsonView({NodeInfo.NodeInfoView.class, NodeInfo.XNodeInfoView.class})
public class ServiceInfo {
private List<String> inbound;
private List<String> outbound;
diff --git a/src/main/java/com/juick/server/api/xnodeinfo2/model/Usage.java b/src/main/java/com/juick/server/api/xnodeinfo2/model/Usage.java
index e04ea48b..f270296f 100644
--- a/src/main/java/com/juick/server/api/xnodeinfo2/model/Usage.java
+++ b/src/main/java/com/juick/server/api/xnodeinfo2/model/Usage.java
@@ -1,5 +1,8 @@
package com.juick.server.api.xnodeinfo2.model;
+import com.fasterxml.jackson.annotation.JsonView;
+
+@JsonView({NodeInfo.NodeInfoView.class, NodeInfo.XNodeInfoView.class})
public class Usage {
private UserStats users;
private int localPosts;
diff --git a/src/main/java/com/juick/server/api/xnodeinfo2/model/UserStats.java b/src/main/java/com/juick/server/api/xnodeinfo2/model/UserStats.java
index 515661e3..cca31be6 100644
--- a/src/main/java/com/juick/server/api/xnodeinfo2/model/UserStats.java
+++ b/src/main/java/com/juick/server/api/xnodeinfo2/model/UserStats.java
@@ -1,5 +1,8 @@
package com.juick.server.api.xnodeinfo2.model;
+import com.fasterxml.jackson.annotation.JsonView;
+
+@JsonView({NodeInfo.NodeInfoView.class, NodeInfo.XNodeInfoView.class})
public class UserStats {
private int total;
private int activeHalfyear;
diff --git a/src/main/java/com/juick/server/configuration/ActivityPubClientConfig.java b/src/main/java/com/juick/server/configuration/ActivityPubClientConfig.java
index 43b638fe..d7d49355 100644
--- a/src/main/java/com/juick/server/configuration/ActivityPubClientConfig.java
+++ b/src/main/java/com/juick/server/configuration/ActivityPubClientConfig.java
@@ -1,11 +1,13 @@
package com.juick.server.configuration;
+import com.juick.server.api.activity.model.Activity;
+import com.juick.server.helpers.HeaderRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import javax.inject.Inject;
+import java.util.Collections;
@Configuration
public class ActivityPubClientConfig {
@@ -13,8 +15,10 @@ public class ActivityPubClientConfig {
ActivityPubClientErrorHandler activityPubClientErrorHandler;
@Bean
public RestTemplate apClient() {
- RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory());
+ RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(activityPubClientErrorHandler);
+ restTemplate.setInterceptors(Collections.singletonList(
+ new HeaderRequestInterceptor("Accept", Activity.ACTIVITY_MEDIA_TYPE)));
return restTemplate;
}
} \ No newline at end of file
diff --git a/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java b/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java
index 5a5d2c7b..68b3d35f 100644
--- a/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java
+++ b/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java
@@ -17,25 +17,15 @@
package com.juick.server.configuration;
-import com.juick.server.WebsocketManager;
import com.juick.server.api.rss.MessagesView;
import com.juick.server.api.rss.RepliesView;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.core.Ordered;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
-import org.springframework.web.socket.config.annotation.EnableWebSocket;
-import org.springframework.web.socket.config.annotation.ServletWebSocketHandlerRegistry;
-import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
-import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
-import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
-
-import javax.annotation.Nonnull;
-import javax.inject.Inject;
/**
* Created by aalexeev on 11/12/16.
@@ -43,24 +33,7 @@ import javax.inject.Inject;
@Configuration
@EnableAsync(proxyTargetClass = true)
@EnableScheduling
-@EnableWebSocket
-public class ApiAppConfiguration implements WebMvcConfigurer, WebSocketConfigurer {
- @Inject
- private WebsocketManager websocketManager;
-
- @Override
- public void registerWebSocketHandlers(@Nonnull WebSocketHandlerRegistry registry) {
- ((ServletWebSocketHandlerRegistry) registry).setOrder(Ordered.HIGHEST_PRECEDENCE);
- registry.addHandler(websocketManager, "/ws/**").setAllowedOrigins("*");
- }
-
- @Bean
- public ServletServerContainerFactoryBean createWebSocketContainer() {
- ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
- container.setMaxTextMessageBufferSize(8192);
- container.setMaxBinaryMessageBufferSize(8192);
- return container;
- }
+public class ApiAppConfiguration implements WebMvcConfigurer {
@Bean
public BeanNameViewResolver beanNameViewResolver() {
return new BeanNameViewResolver();
diff --git a/src/main/java/com/juick/server/configuration/BaseWebConfiguration.java b/src/main/java/com/juick/server/configuration/BaseWebConfiguration.java
index 6a2a8142..c8b88cd1 100644
--- a/src/main/java/com/juick/server/configuration/BaseWebConfiguration.java
+++ b/src/main/java/com/juick/server/configuration/BaseWebConfiguration.java
@@ -17,6 +17,10 @@
package com.juick.server.configuration;
+import com.juick.server.KeystoreManager;
+import com.overzealous.remark.Options;
+import com.overzealous.remark.Remark;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
@@ -36,6 +40,10 @@ import java.util.concurrent.Executors;
@Configuration
public class BaseWebConfiguration implements WebMvcConfigurer, SchedulingConfigurer {
+ @Value("${keystore:juick.p12}")
+ private String keystore;
+ @Value("${keystore_password:secret}")
+ private String keystorePassword;
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
@@ -61,4 +69,14 @@ public class BaseWebConfiguration implements WebMvcConfigurer, SchedulingConfigu
public ExecutorService executorService() {
return Executors.newCachedThreadPool();
}
+ @Bean
+ public KeystoreManager keystoreManager() {
+ return new KeystoreManager(keystore, keystorePassword);
+ }
+ @Bean
+ public Remark remarkConverter() {
+ Options options = new Options();
+ options.inlineLinks = true;
+ return new Remark(options);
+ }
}
diff --git a/src/main/java/com/juick/server/configuration/SecurityConfig.java b/src/main/java/com/juick/server/configuration/SecurityConfig.java
index f53cc531..df0da16e 100644
--- a/src/main/java/com/juick/server/configuration/SecurityConfig.java
+++ b/src/main/java/com/juick/server/configuration/SecurityConfig.java
@@ -17,7 +17,9 @@
package com.juick.server.configuration;
+import com.juick.server.SignatureManager;
import com.juick.service.UserService;
+import com.juick.service.security.HTTPSignatureAuthenticationFilter;
import com.juick.service.security.HashParamAuthenticationFilter;
import com.juick.service.security.JuickUserDetailsService;
import com.juick.service.security.deprecated.RequestParamHashRememberMeServices;
@@ -69,6 +71,20 @@ public class SecurityConfig {
public UserDetailsService userDetailsService() {
return new JuickUserDetailsService(userService);
}
+ @Bean
+ static CorsConfigurationSource corsConfigurationSource() {
+ CorsConfiguration configuration = new CorsConfiguration();
+
+ configuration.setAllowedOrigins(Collections.singletonList("*"));
+ configuration.setAllowedMethods(Arrays.asList("POST", "GET", "PUT", "OPTIONS", "DELETE"));
+ configuration.setAllowedHeaders(Collections.singletonList("*"));
+
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ source.registerCorsConfiguration("/api/**", configuration);
+ source.registerCorsConfiguration("/u/**", configuration);
+ source.registerCorsConfiguration("/n/**", configuration);
+ return source;
+ }
@Configuration
@Order(1)
@@ -79,6 +95,8 @@ public class SecurityConfig {
private String webDomain;
@Resource
private UserService userService;
+ @Resource
+ private SignatureManager signatureManager;
ApiConfig() {
super(true);
}
@@ -95,10 +113,14 @@ public class SecurityConfig {
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**")
.addFilterBefore(apiAuthenticationFilter(), BasicAuthenticationFilter.class)
+ .addFilterBefore(new HTTPSignatureAuthenticationFilter(signatureManager, userService), BasicAuthenticationFilter.class)
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
- .antMatchers("/api/", "/api/messages", "/api/messages/discussions", "/api/users", "/api/thread", "/api/tags", "/api/tlgmbtwbhk", "/api/fbwbhk",
- "/api/skypebotendpoint", "/api/_fblogin", "/api/_vklogin", "/api/_tglogin", "/api/_google", "/api/signup", "/api/inbox", "/api/u/**", "/.well-known/webfinger", "/.well-known/x-nodeinfo2", "/rss/**", "/api/events").permitAll()
+ .antMatchers("/api/", "/api/messages", "/api/avatar", "/api/messages/discussions",
+ "/api/users", "/api/thread", "/api/tags", "/api/tlgmbtwbhk", "/api/fbwbhk",
+ "/api/skypebotendpoint", "/api/_fblogin", "/api/_vklogin", "/api/_tglogin",
+ "/api/_google", "/api/signup", "/api/inbox", "/api/events", "/api/info/**",
+ "/api/nodeinfo/2.0").permitAll()
.anyRequest().hasRole("USER")
.and()
.anonymous().principal(JuickUser.ANONYMOUS_USER).authorities(JuickUser.ANONYMOUS_AUTHORITY)
@@ -122,19 +144,6 @@ public class SecurityConfig {
return new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED);
}
- @Bean
- public CorsConfigurationSource corsConfigurationSource() {
- CorsConfiguration configuration = new CorsConfiguration();
-
- configuration.setAllowedOrigins(Collections.singletonList("*"));
- configuration.setAllowedMethods(Arrays.asList("POST", "GET", "PUT", "OPTIONS", "DELETE"));
- configuration.setAllowedHeaders(Collections.singletonList("*"));
-
- UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
- source.registerCorsConfiguration("/api/**", configuration);
-
- return source;
- }
@Override
public void configure(WebSecurity web) {
web.debug(false);
@@ -182,6 +191,7 @@ public class SecurityConfig {
.anyRequest().permitAll()
.and()
.anonymous().principal(JuickUser.ANONYMOUS_USER).authorities(JuickUser.ANONYMOUS_AUTHORITY)
+ .and().cors().configurationSource(corsConfigurationSource())
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.invalidSessionUrl("/")
diff --git a/src/main/java/com/juick/server/configuration/XMPPConfig.java b/src/main/java/com/juick/server/configuration/XMPPConfig.java
index 2feef286..f9b6f092 100644
--- a/src/main/java/com/juick/server/configuration/XMPPConfig.java
+++ b/src/main/java/com/juick/server/configuration/XMPPConfig.java
@@ -1,23 +1,13 @@
package com.juick.server.configuration;
-import com.juick.server.XMPPConnection;
-import com.juick.server.XMPPServer;
+import com.juick.server.XMPPManager;
import com.juick.server.xmpp.JidConverter;
-import com.juick.server.xmpp.iq.MessageQuery;
-import com.juick.server.xmpp.router.XMPPRouter;
-import com.juick.server.xmpp.s2s.BasicXmppSession;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.DependsOn;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
-import rocks.xmpp.core.session.Extension;
-import rocks.xmpp.core.session.XmppSessionConfiguration;
-import rocks.xmpp.core.session.debug.LogbackDebugger;
-
-import java.time.Duration;
@Configuration
@ConditionalOnProperty("xmppbot_jid")
@@ -25,31 +15,13 @@ public class XMPPConfig {
@Value("${hostname:localhost}")
private String hostname;
@Bean
- public BasicXmppSession session() {
- XmppSessionConfiguration configuration = XmppSessionConfiguration.builder()
- .extensions(Extension.of(com.juick.Message.class), Extension.of(MessageQuery.class))
- .debugger(LogbackDebugger.class)
- .defaultResponseTimeout(Duration.ofMillis(120000))
- .build();
- return BasicXmppSession.create(hostname, configuration);
- }
- @Bean
public static ConversionService conversionService() {
DefaultFormattingConversionService cs = new DefaultFormattingConversionService();
cs.addConverter(new JidConverter());
return cs;
}
@Bean
- public XMPPServer xmppServer() {
- return new XMPPServer();
- }
- @Bean
- public XMPPRouter xmppRouter() {
- return new XMPPRouter();
- }
- @Bean
- @DependsOn("xmppRouter")
- public XMPPConnection xmppConnection() {
- return new XMPPConnection();
+ public XMPPManager xmppConnection() {
+ return new XMPPManager();
}
}
diff --git a/src/main/java/com/juick/server/helpers/HeaderRequestInterceptor.java b/src/main/java/com/juick/server/helpers/HeaderRequestInterceptor.java
new file mode 100644
index 00000000..9121f5ce
--- /dev/null
+++ b/src/main/java/com/juick/server/helpers/HeaderRequestInterceptor.java
@@ -0,0 +1,26 @@
+package com.juick.server.helpers;
+
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+
+import java.io.IOException;
+
+public class HeaderRequestInterceptor implements ClientHttpRequestInterceptor {
+
+ private final String headerName;
+
+ private final String headerValue;
+
+ public HeaderRequestInterceptor(String headerName, String headerValue) {
+ this.headerName = headerName;
+ this.headerValue = headerValue;
+ }
+
+ @Override
+ public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
+ request.getHeaders().set(headerName, headerValue);
+ return execution.execute(request, body);
+ }
+}
diff --git a/src/main/java/com/juick/server/util/ImageUtils.java b/src/main/java/com/juick/server/util/ImageUtils.java
index d16faf8f..2f5d3292 100644
--- a/src/main/java/com/juick/server/util/ImageUtils.java
+++ b/src/main/java/com/juick/server/util/ImageUtils.java
@@ -108,7 +108,7 @@ public class ImageUtils {
}
}
}
- } catch (ImageReadException e) {
+ } catch (ImageReadException | IOException e) {
// failed to read metadata.
// nothing to do here, return image as is.
}
diff --git a/src/main/java/com/juick/server/www/VaryHandler.java b/src/main/java/com/juick/server/www/VaryHandler.java
new file mode 100644
index 00000000..5a1b86a6
--- /dev/null
+++ b/src/main/java/com/juick/server/www/VaryHandler.java
@@ -0,0 +1,14 @@
+package com.juick.server.www;
+
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ModelAttribute;
+
+import javax.servlet.http.HttpServletResponse;
+
+@ControllerAdvice
+public class VaryHandler {
+ @ModelAttribute
+ public void setVaryResponseHeader(HttpServletResponse response) {
+ response.setHeader("Vary", "Accept-Language");
+ }
+}
diff --git a/src/main/java/com/juick/server/www/controllers/AnythingFilter.java b/src/main/java/com/juick/server/www/controllers/AnythingFilter.java
index cdbeafc0..57b298eb 100644
--- a/src/main/java/com/juick/server/www/controllers/AnythingFilter.java
+++ b/src/main/java/com/juick/server/www/controllers/AnythingFilter.java
@@ -60,7 +60,7 @@ public class AnythingFilter extends OncePerRequestFilter {
} else {
com.juick.User user = userService.getUserByName(anything);
if (!user.isAnonymous()) {
- ((HttpServletResponse) servletResponse).sendRedirect("/" + user.getName() + "/?before=" + before);
+ servletResponse.sendRedirect("/" + user.getName() + "/?before=" + before);
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
diff --git a/src/main/java/com/juick/server/www/controllers/MessagesWWW.java b/src/main/java/com/juick/server/www/controllers/MessagesWWW.java
index 1c69db32..4410f591 100644
--- a/src/main/java/com/juick/server/www/controllers/MessagesWWW.java
+++ b/src/main/java/com/juick/server/www/controllers/MessagesWWW.java
@@ -43,7 +43,9 @@ import ru.sape.Sape;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
+import java.net.URI;
import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -97,7 +99,7 @@ public class MessagesWWW {
@CookieValue(name = "sape_cookie", required = false, defaultValue = StringUtils.EMPTY) String sapeCookie,
ModelMap model) throws IOException {
if (tag != null) {
- return "redirect:/tag/" + URLEncoder.encode(tag, CharEncoding.UTF_8);
+ return "redirect:/tag/" + URLEncoder.encode(tag, StandardCharsets.UTF_8);
}
com.juick.User visitor = UserUtils.getCurrentUser();
@@ -182,10 +184,9 @@ public class MessagesWWW {
}
model.addAttribute("nextpage", nextpage);
}
- UriComponents builder = ServletUriComponentsBuilder.fromCurrentRequestUri().build();
- String queryString = builder.getQuery();
- String requestURI = builder.toUri().getPath();
- if (sape.isPresent() && visitor.isAnonymous() && queryString == null) {
+ UriComponents builder = ServletUriComponentsBuilder.fromCurrentRequest().build();
+ URI requestURI = builder.toUri();
+ if (sape.isPresent() && visitor.isAnonymous()) {
String links = sape.get().getPageLinks(requestURI, sapeCookie).render();
model.addAttribute("links", links);
}
@@ -295,17 +296,16 @@ public class MessagesWWW {
nextpage += "&amp;show=" + paramShow;
}
if (paramSearch != null) {
- nextpage += "&amp;search=" + URLEncoder.encode(paramSearch, CharEncoding.UTF_8);
+ nextpage += "&amp;search=" + URLEncoder.encode(paramSearch, StandardCharsets.UTF_8);
}
if (paramTag != null) {
- nextpage += "&amp;tag=" + URLEncoder.encode(paramTag.getName(), CharEncoding.UTF_8);
+ nextpage += "&amp;tag=" + URLEncoder.encode(paramTag.getName(), StandardCharsets.UTF_8);
}
model.addAttribute("nextpage", nextpage);
}
- UriComponents builder = ServletUriComponentsBuilder.fromCurrentRequestUri().build();
- String queryString = builder.getQuery();
- String requestURI = builder.toUri().getPath();
- if (sape.isPresent() && visitor.isAnonymous() && queryString == null) {
+ UriComponents builder = ServletUriComponentsBuilder.fromCurrentRequest().build();
+ URI requestURI = builder.toUri();
+ if (sape.isPresent() && visitor.isAnonymous()) {
String links = sape.get().getPageLinks(requestURI, sapeCookie).render();
model.addAttribute("links", links);
}
@@ -313,7 +313,7 @@ public class MessagesWWW {
}
@GetMapping("/{uname}/tags")
- protected String doGetTags(@PathVariable String uname, ModelMap model) throws IOException {
+ protected String doGetTags(@PathVariable String uname, ModelMap model) {
com.juick.User user = userService.getUserByName(uname);
com.juick.User visitor = UserUtils.getCurrentUser();
if (visitor.isBanned()) {
@@ -332,7 +332,7 @@ public class MessagesWWW {
}
@GetMapping("/{uname}/friends")
- protected String doGetFriends(@PathVariable String uname, ModelMap model) throws IOException {
+ protected String doGetFriends(@PathVariable String uname, ModelMap model) {
com.juick.User user = userService.getUserByName(uname);
com.juick.User visitor = UserUtils.getCurrentUser();
if (visitor.isBanned()) {
@@ -444,13 +444,12 @@ public class MessagesWWW {
model.addAttribute("isSubscribed", tagService.isSubscribed(visitor, paramTag));
model.addAttribute("isInBL", tagService.isInBL(visitor, paramTag));
if (mids.size() >= 20) {
- String nextpage = "/tag/" + URLEncoder.encode(paramTag.getName(), CharEncoding.UTF_8) + "?before=" + mids.get(mids.size() - 1);
+ String nextpage = "/tag/" + URLEncoder.encode(paramTag.getName(), StandardCharsets.UTF_8) + "?before=" + mids.get(mids.size() - 1);
model.addAttribute("nextpage", nextpage);
}
- UriComponents builder = ServletUriComponentsBuilder.fromCurrentRequestUri().build();
- String queryString = builder.getQuery();
- String requestURI = builder.toUri().getPath();
- if (sape.isPresent() && visitor.isAnonymous() && queryString == null) {
+ UriComponents builder = ServletUriComponentsBuilder.fromCurrentRequest().build();
+ URI requestURI = builder.toUri();
+ if (sape.isPresent() && visitor.isAnonymous()) {
String links = sape.get().getPageLinks(requestURI, sapeCookie).render();
model.addAttribute("links", links);
}
@@ -591,10 +590,9 @@ public class MessagesWWW {
}
model.addAttribute("replies", replies);
model.addAttribute("showAdv", visitor.isAnonymous());
- UriComponents builder = ServletUriComponentsBuilder.fromCurrentRequestUri().build();
- String queryString = builder.getQuery();
- String requestURI = builder.toUri().getPath();
- if (sape.isPresent() && visitor.isAnonymous() && queryString == null) {
+ UriComponents builder = ServletUriComponentsBuilder.fromCurrentRequest().build();
+ URI requestURI = builder.toUri();
+ if (sape.isPresent() && visitor.isAnonymous()) {
String links = sape.get().getPageLinks(requestURI, sapeCookie).render();
model.addAttribute("links", links);
}
diff --git a/src/main/java/com/juick/server/www/controllers/Settings.java b/src/main/java/com/juick/server/www/controllers/Settings.java
index 57984aef..d5a21d09 100644
--- a/src/main/java/com/juick/server/www/controllers/Settings.java
+++ b/src/main/java/com/juick/server/www/controllers/Settings.java
@@ -18,7 +18,6 @@ package com.juick.server.www.controllers;
import com.juick.User;
import com.juick.model.NotifyOpts;
-import com.juick.model.UserInfo;
import com.juick.server.util.HttpBadRequestException;
import com.juick.server.util.HttpUtils;
import com.juick.server.util.UserUtils;
@@ -60,8 +59,6 @@ import java.util.stream.IntStream;
public class Settings {
private static final Logger logger = LoggerFactory.getLogger(Settings.class);
- @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String imgDir;
@Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
private String tmpDir;
@Inject
@@ -158,16 +155,15 @@ public class Settings {
}
break;
case "about":
- UserInfo info = new UserInfo();
- info.setFullName(request.getParameter("fullname"));
- info.setCountry(request.getParameter("country"));
- info.setUrl(request.getParameter("url"));
- info.setDescription(request.getParameter("descr"));
+ visitor.setFullName(request.getParameter("fullname"));
+ visitor.setCountry(request.getParameter("country"));
+ visitor.setUrl(request.getParameter("url"));
+ visitor.setDescription(request.getParameter("descr"));
String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, tmpDir).getHost();
if (StringUtils.isNotEmpty(avatarTmpPath)) {
imagesService.saveAvatar(avatarTmpPath, visitor.getUid());
}
- if (userService.updateUserInfo(visitor, info)) {
+ if (userService.updateUserInfo(visitor)) {
result = String.format("<p>Your info is updated.</p><p><a href='/%s/'>Back to blog</a>.</p>", visitor.getName());
}
break;
diff --git a/src/main/java/com/juick/server/www/controllers/SocialLogin.java b/src/main/java/com/juick/server/www/controllers/SocialLogin.java
index bc631a1a..59b1ec0b 100644
--- a/src/main/java/com/juick/server/www/controllers/SocialLogin.java
+++ b/src/main/java/com/juick/server/www/controllers/SocialLogin.java
@@ -79,6 +79,7 @@ public class SocialLogin {
@Inject
private ObjectMapper jsonMapper;
private ServiceBuilder facebookBuilder, twitterBuilder, vkBuilder;
+ private OAuth20Service facebookAuthService, vkAuthService;
@Value("${twitter_consumer_key:appid}")
private String twitterConsumerKey;
@@ -107,6 +108,16 @@ public class SocialLogin {
vkBuilder = new ServiceBuilder(VK_APPID);
UriComponentsBuilder facebookRedirectBuilder = UriComponentsBuilder.fromUriString(baseUri);
facebookRedirectUri = facebookRedirectBuilder.replacePath("/_fblogin").build().toUriString();
+ facebookAuthService = facebookBuilder
+ .apiSecret(FACEBOOK_SECRET)
+ .callback(facebookRedirectUri)
+ .scope("email")
+ .build(FacebookApi.instance());
+ vkAuthService = vkBuilder
+ .apiSecret(VK_SECRET)
+ .scope("friends,wall,offline")
+ .callback(VK_REDIRECT)
+ .build(VkontakteApi.instance());
}
@GetMapping("/_fblogin")
@@ -120,13 +131,7 @@ public class SocialLogin {
state = Utils.getPreviousPageByRequest(request).orElse("https://juick.com/");
}
crosspostService.addFacebookState(fbstate, state);
- OAuth20Service facebookAuthService = facebookBuilder
- .apiSecret(FACEBOOK_SECRET)
- .callback(facebookRedirectUri)
- .scope("email")
- .state(fbstate)
- .build(FacebookApi.instance());
- return "redirect:" + facebookAuthService.getAuthorizationUrl();
+ return "redirect:" + facebookAuthService.getAuthorizationUrl(fbstate);
}
String redirectUrl = crosspostService.verifyFacebookState(state);
@@ -134,31 +139,24 @@ public class SocialLogin {
logger.error("state is missing");
throw new HttpBadRequestException();
}
- OAuth20Service facebookService = facebookBuilder
- .apiKey(FACEBOOK_APPID)
- .apiSecret(FACEBOOK_SECRET)
- .callback(facebookRedirectUri)
- .scope("email")
- .state(state)
- .build(FacebookApi.instance());
- OAuth2AccessToken token = facebookService.getAccessToken(code);
- final OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://graph.facebook.com/v2.10/me?fields=id,name,link,verified,email");
- facebookService.signRequest(token, meRequest);
- String graph = facebookService.execute(meRequest).getBody();
+ OAuth2AccessToken token = facebookAuthService.getAccessToken(code);
+ final OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://graph.facebook.com/v3.2/me?fields=id,name,link,verified,email");
+ facebookAuthService.signRequest(token, meRequest);
+ String graph = facebookAuthService.execute(meRequest).getBody();
if (StringUtils.isBlank(graph)) {
logger.error("FACEBOOK GRAPH ERROR");
throw new HttpBadRequestException();
}
User fb = jsonMapper.readValue(graph, User.class);
long fbID = NumberUtils.toLong(fb.getId(), 0);
- if (fbID == 0 || StringUtils.isBlank(fb.getName()) || StringUtils.isBlank(fb.getLink())) {
- logger.error("Missing required fields, id: {}, name: {}, link: {}", fbID, fb.getName(), fb.getLink());
+ if (fbID == 0 || StringUtils.isBlank(fb.getName())) {
+ logger.error("Missing required fields, id: {}, name: {}", fbID, fb.getName());
throw new HttpBadRequestException();
}
int uid = crosspostService.getUIDbyFBID(fbID);
if (uid > 0) {
- if (!crosspostService.updateFacebookUser(fbID, token.getAccessToken(), fb.getName(), fb.getLink())) {
+ if (!crosspostService.updateFacebookUser(fbID, token.getAccessToken(), fb.getName())) {
logger.error("error updating facebook user, id: {}, token: {}", fbID, token.getAccessToken());
throw new HttpBadRequestException();
}
@@ -166,22 +164,19 @@ public class SocialLogin {
c.setMaxAge(50 * 24 * 60 * 60);
response.addCookie(c);
return "redirect:" + redirectUrl;
- } else if (fb.getVerified()) {
- if (!crosspostService.createFacebookUser(fbID, state, token.getAccessToken(), fb.getName(), fb.getLink())) {
+ } else {
+ if (!crosspostService.createFacebookUser(fbID, state, token.getAccessToken(), fb.getName())) {
if (StringUtils.isNotEmpty(fb.getEmail())) {
- logger.info("found {} for facebook user {}", fb.getEmail(), fb.getLink());
+ logger.info("found {} for facebook user {}", fb.getEmail());
Integer userId = crosspostService.getUIDbyFBID(fbID);
if (!emailService.getEmails(userId, false).contains(fb.getEmail())) {
emailService.addEmail(userId, fb.getEmail());
}
}
- logger.info("email not found for facebook user {}", fb.getLink());
+ logger.info("email not found for facebook user {}", fb.getName());
throw new HttpBadRequestException();
}
return "redirect:/signup?type=fb&hash=" + state;
- } else {
- logger.error("Facebook account is not verified, id: {}", fbID);
- throw new HttpBadRequestException();
}
}
@GetMapping("/_twitter")
@@ -243,13 +238,7 @@ public class SocialLogin {
vkstate = UUID.randomUUID().toString();
Cookie c = new Cookie("vkstate", vkstate);
response.addCookie(c);
- OAuth20Service vkAuthService = vkBuilder
- .apiSecret(VK_SECRET)
- .scope("friends,wall,offline")
- .state(vkstate)
- .callback(VK_REDIRECT)
- .build(VkontakteApi.instance());
- return "redirect:" + vkAuthService.getAuthorizationUrl();
+ return "redirect:" + vkAuthService.getAuthorizationUrl(vkstate);
}
if (StringUtils.isBlank(vkstate) || !vkstate.equals(state)) {
@@ -259,16 +248,11 @@ public class SocialLogin {
c.setMaxAge(0);
response.addCookie(c);
}
-
- OAuth20Service vkService = vkBuilder
- .apiKey(VK_APPID)
- .apiSecret(VK_SECRET)
- .build(VkontakteApi.instance());
- OAuth2AccessToken token = vkService.getAccessToken(code);
+ OAuth2AccessToken token = vkAuthService.getAccessToken(code);
OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://api.vk.com/method/users.get?fields=screen_name&v=5.73");
- vkService.signRequest(token, meRequest);
- String graph = vkService.execute(meRequest).getBody();
+ vkAuthService.signRequest(token, meRequest);
+ String graph = vkAuthService.execute(meRequest).getBody();
com.juick.model.vk.User jsonUser = jsonMapper.readValue(graph, UsersResponse.class).getUsers().get(0);
String vkName = jsonUser.getFirstName() + " " + jsonUser.getLastName();
diff --git a/src/main/java/com/juick/server/xmpp/XMPPStatusPage.java b/src/main/java/com/juick/server/xmpp/XMPPStatusPage.java
deleted file mode 100644
index 231696ec..00000000
--- a/src/main/java/com/juick/server/xmpp/XMPPStatusPage.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.juick.server.xmpp;
-
-import com.juick.server.XMPPServer;
-import com.juick.server.xmpp.helpers.XMPPStatus;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-import rocks.xmpp.addr.Jid;
-import springfox.documentation.annotations.ApiIgnore;
-
-import javax.inject.Inject;
-import java.util.stream.Collectors;
-
-@RestController
-@ConditionalOnProperty("xmppbot_jid")
-public class XMPPStatusPage {
- @Inject
- private XMPPServer xmpp;
- @ApiIgnore
- @RequestMapping(method = RequestMethod.GET, value = "/api/xmpp-status", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public XMPPStatus xmppStatus() {
- XMPPStatus status = new XMPPStatus();
- if (xmpp != null) {
- status.setInbound(xmpp.getInConnections().stream().map(c -> c.from).flatMap(j -> j.stream().map(Jid::getDomain)).collect(Collectors.toList()));
- status.setOutbound(xmpp.getOutConnections().keySet().stream()
- .map(c -> c.to).map(Jid::getDomain).collect(Collectors.toList()));
- }
- return status;
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java b/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java
deleted file mode 100644
index 99d89866..00000000
--- a/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.helpers;
-
-import com.juick.server.xmpp.s2s.ConnectionIn;
-import com.juick.server.xmpp.s2s.ConnectionOut;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * Created by vitalyster on 16.02.2017.
- */
-public class XMPPStatus {
- private List<String> inbound;
- private List<String> outbound;
-
- public List<String> getInbound() {
- return inbound;
- }
-
- public void setInbound(List<String> inbound) {
- this.inbound = inbound;
- }
-
- public List<String> getOutbound() {
- return outbound;
- }
-
- public void setOutbound(List<String> outbound) {
- this.outbound = outbound;
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/router/Handshake.java b/src/main/java/com/juick/server/xmpp/router/Handshake.java
deleted file mode 100644
index 0bc501dd..00000000
--- a/src/main/java/com/juick/server/xmpp/router/Handshake.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-
-/**
- * Created by vitalyster on 30.01.2017.
- */
-public class Handshake {
- private String value;
-
- public static Handshake parse(XmlPullParser parser) throws IOException, XmlPullParserException {
- parser.next();
- Handshake handshake = new Handshake();
- handshake.setValue(XmlUtils.getTagText(parser));
- return handshake;
- }
-
- public String getValue() {
- return value;
- }
-
- public void setValue(String value) {
- this.value = value;
- }
-
- @Override
- public String toString() {
- StringBuilder str = new StringBuilder("<handshake");
- if (getValue() != null) {
- str.append(">").append(getValue()).append("</handshake>");
- } else {
- str.append("/>");
- }
- return str.toString();
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/router/Stream.java b/src/main/java/com/juick/server/xmpp/router/Stream.java
deleted file mode 100644
index 2154edf6..00000000
--- a/src/main/java/com/juick/server/xmpp/router/Stream.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Juick
- * Copyright (C) 2008-2011, Ugnich Anton
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.xmpp.router;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-import rocks.xmpp.addr.Jid;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.time.Instant;
-import java.util.UUID;
-
-/**
- *
- * @author Ugnich Anton
- */
-public abstract class Stream {
-
- public boolean isLoggedIn() {
- return loggedIn;
- }
-
- public void setLoggedIn(boolean loggedIn) {
- this.loggedIn = loggedIn;
- }
-
- public Jid from;
- public Jid to;
- private InputStream is;
- private OutputStream os;
- private XmlPullParserFactory factory;
- protected XmlPullParser parser;
- private OutputStreamWriter writer;
- StreamHandler streamHandler;
- private boolean loggedIn;
- private Instant created;
- private Instant updated;
- String streamId;
- private boolean secured;
-
- public Stream(final Jid from, final Jid to, final InputStream is, final OutputStream os) throws XmlPullParserException {
- this.from = from;
- this.to = to;
- this.is = is;
- this.os = os;
- factory = XmlPullParserFactory.newInstance();
- created = updated = Instant.now();
- streamId = UUID.randomUUID().toString();
- }
-
- public void restartStream() throws XmlPullParserException {
- parser = factory.newPullParser();
- parser.setInput(new InputStreamReader(is, StandardCharsets.UTF_8));
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- writer = new OutputStreamWriter(os, StandardCharsets.UTF_8);
- }
-
- public void connect() {
- try {
- restartStream();
- handshake();
- parse();
- } catch (XmlPullParserException e) {
- StreamError invalidXmlError = new StreamError("invalid-xml");
- send(invalidXmlError.toString());
- connectionFailed(new Exception(invalidXmlError.getCondition()));
- } catch (IOException e) {
- connectionFailed(e);
- }
- }
-
- public void setHandler(final StreamHandler streamHandler) {
- this.streamHandler = streamHandler;
- }
-
- public abstract void handshake() throws XmlPullParserException, IOException;
-
- public void logoff() {
- setLoggedIn(false);
- try {
- writer.flush();
- writer.close();
- //TODO close parser
- } catch (final Exception e) {
- connectionFailed(e);
- }
- }
-
- public void send(final String str) {
- try {
- updated = Instant.now();
- writer.write(str);
- writer.flush();
- } catch (final Exception e) {
- connectionFailed(e);
- }
- }
-
- private void parse() throws IOException, XmlPullParserException {
- while (parser.next() != XmlPullParser.END_DOCUMENT) {
- if (parser.getEventType() == XmlPullParser.IGNORABLE_WHITESPACE) {
- setUpdated();
- }
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
- setUpdated();
- final String tag = parser.getName();
- switch (tag) {
- case "message":
- case "presence":
- case "iq":
- streamHandler.stanzaReceived(XmlUtils.parseToString(parser, false));
- break;
- case "error":
- StreamError error = StreamError.parse(parser);
- connectionFailed(new Exception(error.getCondition()));
- return;
- default:
- XmlUtils.skip(parser);
- break;
- }
- }
- }
-
- /**
- * This method is used to be called on a parser or a connection error.
- * It tries to close the XML-Reader and XML-Writer one last time.
- */
- private void connectionFailed(final Exception ex) {
- if (isLoggedIn()) {
- try {
- writer.close();
- //TODO close parser
- } catch (Exception e) {
- }
- }
- if (streamHandler != null) {
- streamHandler.fail(ex);
- }
- }
-
- public Instant getCreated() {
- return created;
- }
-
- public Instant getUpdated() {
- return updated;
- }
- public String getStreamId() {
- return streamId;
- }
-
- public boolean isSecured() {
- return secured;
- }
-
- public void setSecured(boolean secured) {
- this.secured = secured;
- }
-
- public void setUpdated() {
- this.updated = Instant.now();
- }
-
- public InputStream getInputStream() {
- return is;
- }
-
- public void setInputStream(InputStream is) {
- this.is = is;
- }
-
- public OutputStream getOutputStream() {
- return os;
- }
-
- public void setOutputStream(OutputStream os) {
- this.os = os;
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java b/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java
deleted file mode 100644
index a58adfc5..00000000
--- a/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import org.apache.commons.codec.digest.DigestUtils;
-import org.xmlpull.v1.XmlPullParserException;
-import rocks.xmpp.addr.Jid;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.UUID;
-
-/**
- * Created by vitalyster on 30.01.2017.
- */
-public class StreamComponentServer extends Stream {
-
- private String streamId, secret;
-
- public String getStreamId() {
- return streamId;
- }
-
-
- public StreamComponentServer(InputStream is, OutputStream os, String password) throws XmlPullParserException {
- super(null, null, is, os);
- secret = password;
- streamId = UUID.randomUUID().toString();
- }
- @Override
- public void handshake() throws XmlPullParserException, IOException {
- parser.next();
- if (!parser.getName().equals("stream")
- || !parser.getNamespace(null).equals(StreamNamespaces.NS_COMPONENT_ACCEPT)
- || !parser.getNamespace("stream").equals(StreamNamespaces.NS_STREAM)) {
- throw new IOException("invalid stream");
- }
- Jid domain = Jid.of(parser.getAttributeValue(null, "to"));
- if (streamHandler.filter(null, domain)) {
- send(new XMPPError(XMPPError.Type.cancel, "forbidden").toString());
- throw new IOException("invalid domain");
- }
- from = domain;
- to = domain;
- send(String.format("<stream:stream xmlns:stream='%s' " +
- "xmlns='%s' from='%s' id='%s'>", StreamNamespaces.NS_STREAM, StreamNamespaces.NS_COMPONENT_ACCEPT, from.asBareJid().toEscapedString(), streamId));
- Handshake handshake = Handshake.parse(parser);
- boolean authenticated = handshake.getValue().equals(DigestUtils.sha1Hex(streamId + secret));
- setLoggedIn(authenticated);
- if (!authenticated) {
- send(new XMPPError(XMPPError.Type.cancel, "not-authorized").toString());
- streamHandler.fail(new IOException("stream:stream, failed authentication"));
- return;
- }
- send(new Handshake().toString());
- streamHandler.ready(this);
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/router/StreamError.java b/src/main/java/com/juick/server/xmpp/router/StreamError.java
deleted file mode 100644
index f731f039..00000000
--- a/src/main/java/com/juick/server/xmpp/router/StreamError.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-
-
-/**
- * Created by vitalyster on 03.02.2017.
- */
-public class StreamError {
-
- private String condition;
- private String text;
-
- public StreamError() {}
-
- public StreamError(String condition) {
- this.condition = condition;
- }
-
- public static StreamError parse(XmlPullParser parser) throws IOException, XmlPullParserException {
- StreamError streamError = new StreamError();
- final int initial = parser.getDepth();
- while (true) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG && parser.getDepth() == initial + 1) {
- final String tag = parser.getName();
- final String xmlns = parser.getNamespace();
- if (tag.equals("text") && xmlns.equals(StreamNamespaces.NS_XMPP_STREAMS)) {
- streamError.text = XmlUtils.getTagText(parser);
- } else if (xmlns.equals(StreamNamespaces.NS_XMPP_STREAMS)) {
- streamError.condition = tag;
- } else {
- XmlUtils.skip(parser);
- }
- } else if (eventType == XmlPullParser.END_TAG && parser.getDepth() == initial) {
- break;
- }
- }
- return streamError;
- }
-
- public String getCondition() {
- return condition;
- }
-
- @Override
- public String toString() {
- return String.format("<stream:error><%s xmlns='%s'/></stream:error>", condition, StreamNamespaces.NS_XMPP_STREAMS);
- }
-
- public String getText() {
- return text;
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/router/StreamFeatures.java b/src/main/java/com/juick/server/xmpp/router/StreamFeatures.java
deleted file mode 100644
index e8fc324f..00000000
--- a/src/main/java/com/juick/server/xmpp/router/StreamFeatures.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Juick
- * Copyright (C) 2008-2013, Ugnich Anton
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.xmpp.router;
-
-import java.io.IOException;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-/**
- *
- * @author Ugnich Anton
- */
-public class StreamFeatures {
-
- public static final int NOTAVAILABLE = -1;
- public static final int AVAILABLE = 0;
- public static final int REQUIRED = 1;
- public int STARTTLS = NOTAVAILABLE;
- public int ZLIB = NOTAVAILABLE;
- public int PLAIN = NOTAVAILABLE;
- public int DIGEST_MD5 = NOTAVAILABLE;
- public int REGISTER = NOTAVAILABLE;
- public int EXTERNAL = NOTAVAILABLE;
-
- public static StreamFeatures parse(final XmlPullParser parser) throws XmlPullParserException, IOException {
- StreamFeatures features = new StreamFeatures();
- final int initial = parser.getDepth();
- while (true) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG && parser.getDepth() == initial + 1) {
- final String tag = parser.getName();
- final String xmlns = parser.getNamespace();
- if (tag.equals("starttls") && xmlns != null && xmlns.equals("urn:ietf:params:xml:ns:xmpp-tls")) {
- features.STARTTLS = AVAILABLE;
- while (parser.next() == XmlPullParser.START_TAG) {
- if (parser.getName().equals("required")) {
- features.STARTTLS = REQUIRED;
- } else {
- XmlUtils.skip(parser);
- }
- }
- } else if (tag.equals("compression") && xmlns != null && xmlns.equals("http://jabber.org/features/compress")) {
- while (parser.next() == XmlPullParser.START_TAG) {
- if (parser.getName().equals("method")) {
- final String method = XmlUtils.getTagText(parser).toUpperCase();
- if (method.equals("ZLIB")) {
- features.ZLIB = AVAILABLE;
- }
- } else {
- XmlUtils.skip(parser);
- }
- }
- } else if (tag.equals("mechanisms") && xmlns != null && xmlns.equals("urn:ietf:params:xml:ns:xmpp-sasl")) {
- while (parser.next() == XmlPullParser.START_TAG) {
- if (parser.getName().equals("mechanism")) {
- final String mechanism = XmlUtils.getTagText(parser).toUpperCase();
- if (mechanism.equals("PLAIN")) {
- features.PLAIN = AVAILABLE;
- } else if (mechanism.equals("DIGEST-MD5")) {
- features.DIGEST_MD5 = AVAILABLE;
- } else if (mechanism.equals("EXTERNAL")) {
- features.EXTERNAL = AVAILABLE;
- }
- } else {
- XmlUtils.skip(parser);
- }
- }
- } else if (tag.equals("register") && xmlns != null && xmlns.equals("http://jabber.org/features/iq-register")) {
- features.REGISTER = AVAILABLE;
- XmlUtils.skip(parser);
- } else {
- XmlUtils.skip(parser);
- }
- } else if (eventType == XmlPullParser.END_TAG && parser.getDepth() == initial) {
- break;
- }
- }
- return features;
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/router/StreamHandler.java b/src/main/java/com/juick/server/xmpp/router/StreamHandler.java
deleted file mode 100644
index 048c61ec..00000000
--- a/src/main/java/com/juick/server/xmpp/router/StreamHandler.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import rocks.xmpp.addr.Jid;
-
-/**
- * Created by vitalyster on 01.02.2017.
- */
-public interface StreamHandler {
- void ready(StreamComponentServer componentServer);
- void fail(final Exception ex);
- boolean filter(Jid from, Jid to);
- void stanzaReceived(String stanza);
-}
diff --git a/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java b/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java
deleted file mode 100644
index 1b9b1965..00000000
--- a/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.juick.server.xmpp.router;
-
-public class StreamNamespaces {
- public static final String NS_STREAM = "http://etherx.jabber.org/streams";
- public static final String NS_TLS = "urn:ietf:params:xml:ns:xmpp-tls";
- public static final String NS_DB = "jabber:server:dialback";
- public static final String NS_SERVER = "jabber:server";
- public static final String NS_COMPONENT_ACCEPT = "jabber:component:accept";
- public static final String NS_XMPP_STREAMS = "urn:ietf:params:xml:ns:xmpp-streams";
-}
diff --git a/src/main/java/com/juick/server/xmpp/router/XMPPError.java b/src/main/java/com/juick/server/xmpp/router/XMPPError.java
deleted file mode 100644
index 0cf9a3bc..00000000
--- a/src/main/java/com/juick/server/xmpp/router/XMPPError.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Juick
- * Copyright (C) 2008-2013, ugnich
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.xmpp.router;
-
-import org.apache.commons.text.StringEscapeUtils;
-
-/**
- *
- * @author ugnich
- */
-public class XMPPError {
-
- public static final class Type {
-
- public static final String auth = "auth";
- public static final String cancel = "cancel";
- public static final String continue_ = "continue";
- public static final String modify = "modify";
- public static final String wait = "wait";
- }
- private final static String TagName = "error";
- public String by = null;
- private String type;
- private String condition;
- private String text = null;
-
- public XMPPError(String type, String condition) {
- this.type = type;
- this.condition = condition;
- }
-
- @Override
- public String toString() {
- StringBuilder str = new StringBuilder("<").append(TagName).append("");
- if (by != null) {
- str.append(" by=\"").append(StringEscapeUtils.escapeXml10(by)).append("\"");
- }
- if (type != null) {
- str.append(" type=\"").append(StringEscapeUtils.escapeXml10(type)).append("\"");
- }
-
- if (condition != null) {
- str.append(">");
- str.append("<").append(StringEscapeUtils.escapeXml10(condition)).append(" xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"");
- if (text != null) {
- str.append(">").append(StringEscapeUtils.escapeXml10(text)).append("</").append(StringEscapeUtils.escapeXml10(condition))
- .append(">");
- } else {
- str.append("/>");
- }
- str.append("</").append(TagName).append(">");
- } else {
- str.append("/>");
- }
-
- return str.toString();
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java b/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java
deleted file mode 100644
index 6d67fa9c..00000000
--- a/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import com.juick.server.XMPPServer;
-import com.juick.server.xmpp.s2s.BasicXmppSession;
-import com.juick.server.xmpp.s2s.CacheEntry;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import org.xmlpull.v1.XmlPullParserException;
-import rocks.xmpp.addr.Jid;
-import rocks.xmpp.core.stanza.model.IQ;
-import rocks.xmpp.core.stanza.model.Message;
-import rocks.xmpp.core.stanza.model.Presence;
-import rocks.xmpp.core.stanza.model.Stanza;
-import rocks.xmpp.core.stanza.model.server.ServerIQ;
-import rocks.xmpp.core.stanza.model.server.ServerMessage;
-import rocks.xmpp.core.stanza.model.server.ServerPresence;
-import rocks.xmpp.util.XmppUtils;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ExecutorService;
-
-public class XMPPRouter implements StreamHandler {
- private static final Logger logger = LoggerFactory.getLogger("com.juick.server.xmpp");
-
- @Inject
- private ExecutorService service;
-
- private final List<StreamComponentServer> connections = Collections.synchronizedList(new ArrayList<>());
- private final List<CacheEntry> outCache = new CopyOnWriteArrayList<>();
-
- private ServerSocket listener;
-
- @Inject
- private BasicXmppSession session;
-
- @Value("${router_port:5347}")
- private int routerPort;
-
- @Inject
- private XMPPServer xmppServer;
-
- @PostConstruct
- public void init() {
- logger.info("component router initialized");
- service.submit(() -> {
- try {
- listener = new ServerSocket(routerPort);
- logger.info("component router listening on {}", routerPort);
- while (!listener.isClosed()) {
- if (Thread.currentThread().isInterrupted()) break;
- Socket socket = listener.accept();
- service.submit(() -> {
- try {
- StreamComponentServer client = new StreamComponentServer(socket.getInputStream(), socket.getOutputStream(), "secret");
- addConnectionIn(client);
- client.setHandler(this);
- client.connect();
- } catch (IOException e) {
- logger.error("component error", e);
- } catch (XmlPullParserException e) {
- e.printStackTrace();
- }
- });
- }
- } catch (SocketException e) {
- // shutdown
- } catch (IOException e) {
- logger.warn("io exception", e);
- }
- });
- }
-
- @PreDestroy
- public void close() throws Exception {
- if (!listener.isClosed()) {
- listener.close();
- }
- synchronized (getConnections()) {
- for (Iterator<StreamComponentServer> i = getConnections().iterator(); i.hasNext(); ) {
- StreamComponentServer c = i.next();
- c.logoff();
- i.remove();
- }
- }
- service.shutdown();
- logger.info("XMPP router destroyed");
- }
-
- private void addConnectionIn(StreamComponentServer c) {
- synchronized (getConnections()) {
- getConnections().add(c);
- }
- }
-
- private void sendOut(Stanza s) {
- try {
- StringWriter stanzaWriter = new StringWriter();
- XMLStreamWriter xmppStreamWriter = XmppUtils.createXmppStreamWriter(
- session.getConfiguration().getXmlOutputFactory().createXMLStreamWriter(stanzaWriter));
- session.createMarshaller().marshal(s, xmppStreamWriter);
- xmppStreamWriter.flush();
- xmppStreamWriter.close();
- String xml = stanzaWriter.toString();
- logger.info("XMPPRouter (out): {}", xml);
- sendOut(s.getTo().getDomain(), xml);
- } catch (XMLStreamException | JAXBException e1) {
- logger.info("jaxb exception", e1);
- }
- }
-
- private void sendOut(String hostname, String xml) {
- boolean haveAnyConn = false;
-
- StreamComponentServer connOut = null;
- synchronized (getConnections()) {
- for (StreamComponentServer c : getConnections()) {
- if (c.to != null && c.to.getDomain().equals(hostname)) {
- if (c.isLoggedIn()) {
- connOut = c;
- break;
- } else {
- logger.info("bouncing stanza to {} component until it will be ready", hostname);
- boolean haveCache = false;
- for (CacheEntry entry : outCache) {
- if (entry.hostname != null && entry.hostname.equals(hostname)) {
- entry.xml += xml;
- entry.updated = Instant.now();
- haveCache = true;
- break;
- }
- }
- if (!haveCache) {
- outCache.add(new CacheEntry(Jid.of(hostname), xml));
- }
- }
- }
- }
- }
- if (connOut != null) {
- connOut.send(xml);
- return;
- }
- xmppServer.sendOut(Jid.of(hostname), xml);
-
- }
-
- public List<StreamComponentServer> getConnections() {
- return connections;
- }
-
- private Stanza parse(String xml) {
- try {
- Unmarshaller unmarshaller = session.createUnmarshaller();
- return (Stanza)unmarshaller.unmarshal(new StringReader(xml));
- } catch (JAXBException e) {
- logger.error("JAXB exception", e);
- }
- return null;
- }
- @Override
- public void stanzaReceived(String stanza) {
- Stanza input = parse(stanza);
- if (input instanceof Message) {
- sendOut(ServerMessage.from((Message)input));
- } else if (input instanceof IQ) {
- sendOut(ServerIQ.from((IQ)input));
- } else {
- sendOut(ServerPresence.from((Presence) input));
- }
- }
-
- public String getFromCache(Jid to) {
- final String[] cache = new String[1];
- outCache.stream().filter(c -> c.hostname != null && c.hostname.equals(to)).findFirst().ifPresent(c -> {
- cache[0] = c.xml;
- outCache.remove(c);
- });
- return cache[0];
- }
-
- @Override
- public void ready(StreamComponentServer componentServer) {
- logger.info("component {} ready", componentServer.to);
- String cache = getFromCache(componentServer.to);
- if (cache != null) {
- logger.debug("sending cache to {}", componentServer.to);
- componentServer.send(cache);
- }
- }
-
- @Override
- public void fail(Exception e) {
-
- }
-
- @Override
- public boolean filter(Jid jid, Jid jid1) {
- return false;
- }
-} \ No newline at end of file
diff --git a/src/main/java/com/juick/server/xmpp/router/XmlUtils.java b/src/main/java/com/juick/server/xmpp/router/XmlUtils.java
deleted file mode 100644
index 7579489f..00000000
--- a/src/main/java/com/juick/server/xmpp/router/XmlUtils.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Juick
- * Copyright (C) 2008-2011, Ugnich Anton
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.xmpp.router;
-
-import java.io.IOException;
-
-import org.apache.commons.text.StringEscapeUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-/**
- *
- * @author Ugnich Anton
- */
-public class XmlUtils {
-
- public static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
- String tag = parser.getName();
- while (parser.getName() != null && !(parser.next() == XmlPullParser.END_TAG && parser.getName().equals(tag))) {
- }
- }
-
- public static String getTagText(XmlPullParser parser) throws XmlPullParserException, IOException {
- String ret = "";
- String tag = parser.getName();
-
- if (parser.next() == XmlPullParser.TEXT) {
- ret = parser.getText();
- }
-
- while (!(parser.getEventType() == XmlPullParser.END_TAG && parser.getName().equals(tag))) {
- parser.next();
- }
-
- return ret;
- }
-
- public static String parseToString(XmlPullParser parser, boolean skipXMLNS) throws XmlPullParserException, IOException {
- String tag = parser.getName();
- StringBuilder ret = new StringBuilder("<").append(tag);
-
- // skipXMLNS for xmlns="jabber:client"
-
- String ns = parser.getNamespace();
- if (!skipXMLNS && ns != null && !ns.isEmpty()) {
- ret.append(" xmlns=\"").append(ns).append("\"");
- }
-
- for (int i = 0; i < parser.getAttributeCount(); i++) {
- String attr = parser.getAttributeName(i);
- if ((!skipXMLNS || !attr.equals("xmlns")) && !attr.contains(":")) {
- ret.append(" ").append(attr).append("=\"").append(StringEscapeUtils.escapeXml10(parser.getAttributeValue(i))).append("\"");
- }
- }
- ret.append(">");
-
- while (!(parser.next() == XmlPullParser.END_TAG && parser.getName().equals(tag))) {
- int event = parser.getEventType();
- if (event == XmlPullParser.START_TAG) {
- if (!parser.getName().contains(":")) {
- ret.append(parseToString(parser, false));
- } else {
- skip(parser);
- }
- } else if (event == XmlPullParser.TEXT) {
- ret.append(StringEscapeUtils.escapeXml10(parser.getText()));
- }
- }
-
- ret.append("</").append(tag).append(">");
- return ret.toString();
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java b/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java
deleted file mode 100644
index ae28f827..00000000
--- a/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import rocks.xmpp.addr.Jid;
-import rocks.xmpp.core.XmppException;
-import rocks.xmpp.core.session.XmppSession;
-import rocks.xmpp.core.session.XmppSessionConfiguration;
-import rocks.xmpp.core.stanza.model.IQ;
-import rocks.xmpp.core.stanza.model.Message;
-import rocks.xmpp.core.stanza.model.Presence;
-import rocks.xmpp.core.stanza.model.server.ServerIQ;
-import rocks.xmpp.core.stanza.model.server.ServerMessage;
-import rocks.xmpp.core.stanza.model.server.ServerPresence;
-import rocks.xmpp.core.stream.model.StreamElement;
-
-/**
- * Created by vitalyster on 06.02.2017.
- */
-public class BasicXmppSession extends XmppSession {
- protected BasicXmppSession(String xmppServiceDomain, XmppSessionConfiguration configuration) {
- super(xmppServiceDomain, configuration);
- }
-
- public static BasicXmppSession create(String xmppServiceDomain, XmppSessionConfiguration configuration) {
- BasicXmppSession session = new BasicXmppSession(xmppServiceDomain, configuration);
- notifyCreationListeners(session);
- return session;
- }
-
- @Override
- public void connect(Jid from) throws XmppException {
-
- }
-
- @Override
- public Jid getConnectedResource() {
- return null;
- }
-
- @Override
- protected StreamElement prepareElement(StreamElement element) {
- if (element instanceof Message) {
- element = ServerMessage.from((Message) element);
- } else if (element instanceof Presence) {
- element = ServerPresence.from((Presence) element);
- } else if (element instanceof IQ) {
- element = ServerIQ.from((IQ) element);
- }
-
- return element;
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java b/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java
deleted file mode 100644
index 33e875bd..00000000
--- a/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import rocks.xmpp.addr.Jid;
-
-import java.time.Instant;
-
-/**
- *
- * @author ugnich
- */
-public class CacheEntry {
-
- public Jid hostname;
- public Instant created;
- public Instant updated;
- public String xml;
-
- public CacheEntry(Jid hostname, String xml) {
- this.hostname = hostname;
- this.created = this.updated =Instant.now();
- this.xml = xml;
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/s2s/Connection.java b/src/main/java/com/juick/server/xmpp/s2s/Connection.java
deleted file mode 100644
index 4fa8e741..00000000
--- a/src/main/java/com/juick/server/xmpp/s2s/Connection.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.juick.server.XMPPServer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.net.Socket;
-import java.nio.charset.StandardCharsets;
-import java.time.Instant;
-import java.util.UUID;
-
-/**
- *
- * @author ugnich
- */
-public class Connection {
-
- protected static final Logger logger = LoggerFactory.getLogger(Connection.class);
-
- public String streamID;
- public Instant created;
- public Instant updated;
- public long bytesLocal = 0;
- public long packetsLocal = 0;
- XMPPServer xmpp;
- private Socket socket;
- public static final String NS_DB = "jabber:server:dialback";
- public static final String NS_TLS = "urn:ietf:params:xml:ns:xmpp-tls";
- public static final String NS_SASL = "urn:ietf:params:xml:ns:xmpp-sasl";
- public static final String NS_STREAM = "http://etherx.jabber.org/streams";
- XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
- XmlPullParser parser = factory.newPullParser();
- OutputStreamWriter writer;
- private boolean secured = false;
- private boolean authenticated = false;
- private boolean trusted = false;
-
-
-
- public Connection(XMPPServer xmpp) throws XmlPullParserException {
- this.xmpp = xmpp;
- created = updated = Instant.now();
- }
-
- public void logParser() {
- if (streamID == null) {
- return;
- }
- String tag = "IN: <" + parser.getName();
- for (int i = 0; i < parser.getAttributeCount(); i++) {
- tag += " " + parser.getAttributeName(i) + "=\"" + parser.getAttributeValue(i) + "\"";
- }
- tag += ">...</" + parser.getName() + ">\n";
- logger.trace(tag);
- }
-
- public void sendStanza(String xml) {
- if (streamID != null) {
- logger.trace("OUT: {}\n", xml);
- }
- try {
- writer.write(xml);
- writer.flush();
- } catch (IOException e) {
- logger.error("send stanza failed", e);
- }
-
- updated = Instant.now();
- bytesLocal += xml.length();
- packetsLocal++;
- }
-
- public void closeConnection() {
- if (streamID != null) {
- logger.debug("closing stream {}", streamID);
- }
-
- try {
- writer.write("</stream:stream>");
- } catch (Exception e) {
- }
-
- try {
- writer.close();
- } catch (Exception e) {
- }
-
- try {
- socket.close();
- } catch (Exception e) {
- }
- }
-
- public boolean isSecured() {
- return secured;
- }
-
- public void setSecured(boolean secured) {
- this.secured = secured;
- }
-
- public void restartParser() throws XmlPullParserException, IOException {
- streamID = UUID.randomUUID().toString();
- parser = factory.newPullParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new InputStreamReader(socket.getInputStream()));
- writer = new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8);
- }
-
- @JsonIgnore
- public Socket getSocket() {
- return socket;
- }
-
- public void setSocket(Socket socket) {
- this.socket = socket;
- }
-
- public boolean isAuthenticated() {
- return authenticated;
- }
-
- public void setAuthenticated(boolean authenticated) {
- this.authenticated = authenticated;
- }
-
- public boolean isTrusted() {
- return trusted;
- }
-
- public void setTrusted(boolean trusted) {
- this.trusted = trusted;
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java b/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java
deleted file mode 100644
index 72c3ba8d..00000000
--- a/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import com.juick.server.XMPPServer;
-import com.juick.server.xmpp.router.StreamError;
-import com.juick.server.xmpp.router.XmlUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import rocks.xmpp.addr.Jid;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.net.Socket;
-import java.net.SocketException;
-import java.time.Instant;
-import java.util.Arrays;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.stream.Collectors;
-
-/**
- * @author ugnich
- */
-public class ConnectionIn extends Connection implements Runnable {
-
- final public List<Jid> from = new CopyOnWriteArrayList<>();
- public Instant received;
- public long packetsRemote = 0;
- ConnectionListener listener;
-
- public ConnectionIn(XMPPServer xmpp, Socket socket) throws XmlPullParserException, IOException {
- super(xmpp);
- this.setSocket(socket);
- restartParser();
- }
-
- @Override
- public void run() {
- try {
- parser.next(); // stream:stream
- updateTsRemoteData();
- if (!parser.getName().equals("stream")
- || !parser.getNamespace("stream").equals(NS_STREAM)) {
-// || !parser.getAttributeValue(null, "version").equals("1.0")
-// || !parser.getAttributeValue(null, "to").equals(Main.HOSTNAME)) {
- throw new Exception(String.format("stream from %s invalid", getSocket().getRemoteSocketAddress()));
- }
- streamID = parser.getAttributeValue(null, "id");
- if (streamID == null) {
- streamID = UUID.randomUUID().toString();
- }
- boolean xmppversionnew = parser.getAttributeValue(null, "version") != null;
- String from = parser.getAttributeValue(null, "from");
-
- if (Arrays.asList(xmpp.bannedHosts).contains(from)) {
- closeConnection();
- return;
- }
- sendOpenStream(from, xmppversionnew);
-
- while (parser.next() != XmlPullParser.END_DOCUMENT) {
- updateTsRemoteData();
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
- logParser();
-
- packetsRemote++;
-
- String tag = parser.getName();
- if (tag.equals("result") && parser.getNamespace().equals(NS_DB)) {
- String dfrom = parser.getAttributeValue(null, "from");
- String to = parser.getAttributeValue(null, "to");
- logger.debug("stream from {} to {} {} asking for dialback", dfrom, to, streamID);
- if (dfrom.endsWith(xmpp.getJid().toEscapedString()) && (dfrom.equals(xmpp.getJid().toEscapedString())
- || dfrom.endsWith("." + xmpp.getJid()))) {
- logger.warn("stream from {} is invalid", dfrom);
- break;
- }
- if (to != null && to.equals(xmpp.getJid().toEscapedString())) {
- String dbKey = XmlUtils.getTagText(parser);
- updateTsRemoteData();
- xmpp.startDialback(Jid.of(dfrom), streamID, dbKey);
- } else {
- logger.warn("stream from " + dfrom + " " + streamID + " invalid to " + to);
- break;
- }
- } else if (tag.equals("verify") && parser.getNamespace().equals(NS_DB)) {
- String vfrom = parser.getAttributeValue(null, "from");
- String vto = parser.getAttributeValue(null, "to");
- String vid = parser.getAttributeValue(null, "id");
- String vkey = XmlUtils.getTagText(parser);
- updateTsRemoteData();
- final boolean[] valid = {false};
- if (vfrom != null && vto != null && vid != null && vkey != null) {
- xmpp.getConnectionOut(Jid.of(vfrom), false).ifPresent(c -> {
- String dialbackKey = c.dbKey;
- valid[0] = vkey.equals(dialbackKey);
- });
- }
- if (valid[0]) {
- sendStanza("<db:verify from='" + vto + "' to='" + vfrom + "' id='" + vid + "' type='valid'/>");
- logger.debug("stream from {} {} dialback verify valid", vfrom, streamID);
- setAuthenticated(true);
- } else {
- sendStanza("<db:verify from='" + vto + "' to='" + vfrom + "' id='" + vid + "' type='invalid'/>");
- logger.warn("stream from {} {} dialback verify invalid", vfrom, streamID);
- }
- } else if (tag.equals("presence") && checkFromTo(parser) && isAuthenticated()) {
- String xml = XmlUtils.parseToString(parser, false);
- logger.debug("stream {} presence: {}", streamID, xml);
- xmpp.onStanzaReceived(xml);
- } else if (tag.equals("message") && checkFromTo(parser)) {
- updateTsRemoteData();
- String xml = XmlUtils.parseToString(parser, false);
- logger.debug("stream {} message: {}", streamID, xml);
- xmpp.onStanzaReceived(xml);
-
- } else if (tag.equals("iq") && checkFromTo(parser) && isAuthenticated()) {
- updateTsRemoteData();
- String type = parser.getAttributeValue(null, "type");
- String xml = XmlUtils.parseToString(parser, false);
- if (type == null || !type.equals("error")) {
- logger.debug("stream {} iq: {}", streamID, xml);
- xmpp.onStanzaReceived(xml);
- }
- } else if (!isSecured() && tag.equals("starttls") && !isAuthenticated()) {
- listener.starttls(this);
- } else if (isSecured() && tag.equals("stream") && parser.getNamespace().equals(NS_STREAM)) {
- sendOpenStream(null, true);
- } else if (isSecured() && tag.equals("auth") && parser.getNamespace().equals(NS_SASL)
- && parser.getAttributeValue(null, "mechanism").equals("EXTERNAL")
- && !isAuthenticated() && isTrusted()) {
- sendStanza("<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
- logger.info("stream {} authenticated externally", streamID);
- this.from.add(Jid.of(from));
- setAuthenticated(true);
- restartParser();
- } else if (tag.equals("error")) {
- StreamError streamError = StreamError.parse(parser);
- logger.debug("Stream error {} from {}: {}", streamError.getCondition(), streamID, streamError.getText());
- xmpp.removeConnectionIn(this);
- closeConnection();
- } else {
- String unhandledStanza = XmlUtils.parseToString(parser, true);
- logger.warn("Unhandled stanza from {}: {}", streamID, unhandledStanza);
- }
- }
- logger.warn("stream {} finished", streamID);
- xmpp.removeConnectionIn(this);
- closeConnection();
- } catch (EOFException | SocketException ex) {
- logger.debug("stream {} closed (dirty)", streamID);
- xmpp.removeConnectionIn(this);
- closeConnection();
- } catch (Exception e) {
- logger.debug("stream {} error {}", streamID, e);
- xmpp.removeConnectionIn(this);
- closeConnection();
- }
- }
-
- void updateTsRemoteData() {
- received = Instant.now();
- }
-
- void sendOpenStream(String from, boolean xmppversionnew) throws IOException {
- String openStream = "<?xml version='1.0'?><stream:stream xmlns='jabber:server' " +
- "xmlns:stream='http://etherx.jabber.org/streams' xmlns:db='jabber:server:dialback' from='" +
- xmpp.getJid().toEscapedString() + "' id='" + streamID + "' version='1.0'>";
- if (xmppversionnew) {
- openStream += "<stream:features>";
- if (listener != null && listener.isTlsAvailable() && !Arrays.asList(xmpp.brokenSSLhosts).contains(from)) {
- if (!isSecured()) {
- openStream += "<starttls xmlns='" + NS_TLS + "'><optional/></starttls>";
- } else if (!isAuthenticated() && isTrusted()) {
- openStream += "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" +
- "<mechanism>EXTERNAL</mechanism>" +
- "</mechanisms>";
- }
- }
- openStream += "</stream:features>";
- }
- sendStanza(openStream);
- }
-
- public void sendDialbackResult(Jid sfrom, String type) {
- sendStanza("<db:result from='" + xmpp.getJid().toEscapedString() + "' to='" + sfrom + "' type='" + type + "'/>");
- if (type.equals("valid")) {
- from.add(sfrom);
- logger.debug("stream from {} {} ready", sfrom, streamID);
- setAuthenticated(true);
- }
- }
-
- boolean checkFromTo(XmlPullParser parser) throws Exception {
- String cfrom = parser.getAttributeValue(null, "from");
- String cto = parser.getAttributeValue(null, "to");
- if (StringUtils.isNotEmpty(cfrom) && StringUtils.isNotEmpty(cto)) {
- Jid jidfrom = Jid.of(cfrom);
- for (Jid aFrom : from) {
- if (aFrom.equals(Jid.of(jidfrom.getDomain()))) {
- return true;
- }
- }
- }
- logger.warn("rejected from {}, to {}, stream {}", cfrom, cto, from.stream().collect(Collectors.joining(",")));
- return false;
- }
- public void setListener(ConnectionListener listener) {
- this.listener = listener;
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java b/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java
deleted file mode 100644
index 4c32b9ae..00000000
--- a/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.juick.server.xmpp.s2s;
-
-
-import com.juick.server.xmpp.router.StreamError;
-
-public interface ConnectionListener {
- boolean isTlsAvailable();
- void starttls(ConnectionIn connection);
- void proceed(ConnectionOut connection);
- void verify(ConnectionOut connection, String from, String type, String sid);
- void dialbackError(ConnectionOut connection, StreamError error);
- void finished(ConnectionOut connection, boolean dirty);
- void exception(ConnectionOut connection, Exception ex);
- void ready(ConnectionOut connection);
- boolean securing(ConnectionOut connection);
-}
diff --git a/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java b/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java
deleted file mode 100644
index be485ab1..00000000
--- a/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import com.juick.server.xmpp.router.Stream;
-import com.juick.server.xmpp.router.StreamError;
-import com.juick.server.xmpp.router.StreamFeatures;
-import com.juick.server.xmpp.router.XmlUtils;
-import com.juick.server.xmpp.s2s.util.DialbackUtils;
-import org.apache.commons.codec.Charsets;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.text.RandomStringGenerator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.xmlpull.v1.XmlPullParser;
-import rocks.xmpp.addr.Jid;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.SocketException;
-import java.util.UUID;
-
-import static com.juick.server.xmpp.router.StreamNamespaces.NS_STREAM;
-import static com.juick.server.xmpp.s2s.Connection.NS_SASL;
-
-/**
- * @author ugnich
- */
-public class ConnectionOut extends Stream {
- protected static final Logger logger = LoggerFactory.getLogger(ConnectionOut.class);
- public static final String NS_TLS = "urn:ietf:params:xml:ns:xmpp-tls";
- public static final String NS_DB = "jabber:server:dialback";
- private boolean secured = false;
- private boolean trusted = false;
- public boolean streamReady = false;
- String checkSID = null;
- String dbKey = null;
- private String streamID;
- ConnectionListener listener;
- RandomStringGenerator generator = new RandomStringGenerator.Builder().withinRange('a', 'z').build();
-
- public ConnectionOut(Jid from, Jid to, InputStream is, OutputStream os, String checkSID, String dbKey) throws Exception {
- super(from, to, is, os);
- this.to = to;
- this.checkSID = checkSID;
- this.dbKey = dbKey;
- if (dbKey == null) {
- this.dbKey = DialbackUtils.generateDialbackKey(generator.generate(15), to, from, streamID);
- }
- streamID = UUID.randomUUID().toString();
- }
-
- public void sendOpenStream() throws IOException {
- send("<?xml version='1.0'?><stream:stream xmlns='jabber:server' id='" + streamID +
- "' xmlns:stream='http://etherx.jabber.org/streams' xmlns:db='jabber:server:dialback' from='" +
- from.toEscapedString() + "' to='" + to.toEscapedString() + "' version='1.0'>");
- }
-
- void processDialback() throws Exception {
- if (checkSID != null) {
- sendDialbackVerify(checkSID, dbKey);
- }
- send("<db:result from='" + from.toEscapedString() + "' to='" + to.toEscapedString() + "'>" +
- dbKey + "</db:result>");
- }
-
- @Override
- public void handshake() {
- try {
- restartStream();
-
- sendOpenStream();
-
- parser.next(); // stream:stream
- streamID = parser.getAttributeValue(null, "id");
- if (streamID == null || streamID.isEmpty()) {
- throw new Exception("stream to " + to + " invalid first packet");
- }
-
- logger.debug("stream to {} {} open", to, streamID);
- boolean xmppversionnew = parser.getAttributeValue(null, "version") != null;
- if (!xmppversionnew) {
- processDialback();
- }
-
- while (parser.next() != XmlPullParser.END_DOCUMENT) {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
-
- String tag = parser.getName();
- if (tag.equals("result") && parser.getNamespace().equals(NS_DB)) {
- String type = parser.getAttributeValue(null, "type");
- if (type != null && type.equals("valid")) {
- streamReady = true;
- listener.ready(this);
- } else {
- logger.warn("stream to {} {} dialback fail", to, streamID);
- }
- XmlUtils.skip(parser);
- } else if (tag.equals("verify") && parser.getNamespace().equals(NS_DB)) {
- String from = parser.getAttributeValue(null, "from");
- String type = parser.getAttributeValue(null, "type");
- String sid = parser.getAttributeValue(null, "id");
- listener.verify(this, from, type, sid);
- XmlUtils.skip(parser);
- } else if (tag.equals("features") && parser.getNamespace().equals(NS_STREAM)) {
- StreamFeatures features = StreamFeatures.parse(parser);
- if (listener != null && !secured && features.STARTTLS >= 0
- && listener.securing(this)) {
- logger.debug("stream to {} {} securing", to.toEscapedString(), streamID);
- send("<starttls xmlns=\"" + NS_TLS + "\" />");
- } else if (secured && features.EXTERNAL >=0) {
- String authid = Base64.encodeBase64String(from.toEscapedString().getBytes(Charsets.UTF_8));
- send(String.format("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='EXTERNAL'>%s</auth>", authid));
- } else if (secured && streamReady) {
- listener.ready(this);
- } else {
- processDialback();
- }
- } else if (tag.equals("proceed") && parser.getNamespace().equals(NS_TLS)) {
- listener.proceed(this);
- } else if (tag.equals("success") && parser.getNamespace().equals(NS_SASL)) {
- streamReady = true;
- restartStream();
- sendOpenStream();
- } else if (secured && tag.equals("stream") && parser.getNamespace().equals(NS_STREAM)) {
- streamID = parser.getAttributeValue(null, "id");
- } else if (tag.equals("error")) {
- StreamError streamError = StreamError.parse(parser);
- listener.dialbackError(this, streamError);
- } else {
- String unhandledStanza = XmlUtils.parseToString(parser, false);
- logger.warn("Unhandled stanza from {} {} : {}", to, streamID, unhandledStanza);
- }
- }
- listener.finished(this, false);
- } catch (EOFException | SocketException eofex) {
- listener.finished(this, true);
- } catch (Exception e) {
- listener.exception(this, e);
- }
- }
-
- public void sendDialbackVerify(String sid, String key) {
- send("<db:verify from='" + from.toEscapedString() + "' to='" + to + "' id='" + sid + "'>" +
- key + "</db:verify>");
- }
- public void setListener(ConnectionListener listener) {
- this.listener = listener;
- }
-
- public String getStreamID() {
- return streamID;
- }
-
- public boolean isSecured() {
- return secured;
- }
-
- public void setSecured(boolean secured) {
- this.secured = secured;
- }
-
- public boolean isTrusted() {
- return trusted;
- }
-
- public void setTrusted(boolean trusted) {
- this.trusted = trusted;
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java b/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java
deleted file mode 100644
index 1367d333..00000000
--- a/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import org.apache.commons.lang3.math.NumberUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.InetSocketAddress;
-import java.util.Hashtable;
-import java.util.Random;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-
-/**
- *
- * @author ugnich
- */
-public class DNSQueries {
-
- private static final Logger logger = LoggerFactory.getLogger(DNSQueries.class);
-
- private static Random rand = new Random();
-
- public static InetSocketAddress getServerAddress(String hostname) {
-
- String host = hostname;
- int port = 5269;
-
- Hashtable<String, String> env = new Hashtable<>(5);
- env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
- try {
- DirContext ctx = new InitialDirContext(env);
- Attribute att = ctx.getAttributes("_xmpp-server._tcp." + hostname, new String[]{"SRV"}).get("SRV");
-
- if (att != null && att.size() > 0) {
- int i = rand.nextInt(att.size());
- String srv[] = att.get(i).toString().split(" ");
- port = NumberUtils.toInt(srv[2], 5269);
- host = srv[3];
- }
- ctx.close();
- } catch (NamingException e) {
- logger.debug("SRV record for {} is not resolved, falling back to A record", hostname);
- }
- return new InetSocketAddress(host, port);
- }
-}
diff --git a/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java b/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java
deleted file mode 100644
index 6932298f..00000000
--- a/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-
-import rocks.xmpp.core.stanza.model.Stanza;
-
-/**
- * Created by vitalyster on 07.12.2016.
- */
-public interface StanzaListener {
- void stanzaReceived(Stanza xmlValue);
-}
diff --git a/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java b/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java
deleted file mode 100644
index d25dbad8..00000000
--- a/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s.util;
-
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.codec.digest.HmacAlgorithms;
-import org.apache.commons.codec.digest.HmacUtils;
-import rocks.xmpp.addr.Jid;
-
-/**
- * Created by vitalyster on 05.12.2016.
- */
-public class DialbackUtils {
- private DialbackUtils() {
- throw new IllegalStateException();
- }
-
- public static String generateDialbackKey(String secret, Jid to, Jid from, String id) {
- return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, DigestUtils.sha256(secret))
- .hmacHex(to.toEscapedString() + " " + from.toEscapedString() + " " + id);
- }
-}
diff --git a/src/main/java/com/juick/service/CrosspostService.java b/src/main/java/com/juick/service/CrosspostService.java
index 99911250..28b9e8ab 100644
--- a/src/main/java/com/juick/service/CrosspostService.java
+++ b/src/main/java/com/juick/service/CrosspostService.java
@@ -60,9 +60,9 @@ public interface CrosspostService {
int getUIDbyFBID(long fbID);
- boolean createFacebookUser(long fbID, String loginhash, String token, String fbName, String fbLink);
+ boolean createFacebookUser(long fbID, String loginhash, String token, String fbName);
- boolean updateFacebookUser(long fbID, String token, String fbName, String fbLink);
+ boolean updateFacebookUser(long fbID, String token, String fbName);
int getUIDbyVKID(long vkID);
diff --git a/src/main/java/com/juick/service/CrosspostServiceImpl.java b/src/main/java/com/juick/service/CrosspostServiceImpl.java
index d190faba..0eeb8c78 100644
--- a/src/main/java/com/juick/service/CrosspostServiceImpl.java
+++ b/src/main/java/com/juick/service/CrosspostServiceImpl.java
@@ -180,16 +180,16 @@ public class CrosspostServiceImpl extends BaseJdbcService implements CrosspostSe
@Transactional
@Override
- public boolean createFacebookUser(long fbID, String loginhash, String token, String fbName, String fbLink) {
- return getJdbcTemplate().update("UPDATE facebook SET fb_id=?, access_token=?, fb_name=?, fb_link=? WHERE loginhash=?",
- fbID, token, fbName, fbLink, loginhash) > 0;
+ public boolean createFacebookUser(long fbID, String loginhash, String token, String fbName) {
+ return getJdbcTemplate().update("UPDATE facebook SET fb_id=?, access_token=?, fb_name=? WHERE loginhash=?",
+ fbID, token, fbName, loginhash) > 0;
}
@Transactional
@Override
- public boolean updateFacebookUser(long fbID, String token, String fbName, String fbLink) {
- return getJdbcTemplate().update("UPDATE facebook SET access_token=?,fb_name=?,fb_link=? WHERE fb_id=?",
- token, fbName, fbLink, fbID) > 0;
+ public boolean updateFacebookUser(long fbID, String token, String fbName) {
+ return getJdbcTemplate().update("UPDATE facebook SET access_token=?,fb_name=? WHERE fb_id=?",
+ token, fbName, fbID) > 0;
}
@Transactional(readOnly = true)
diff --git a/src/main/java/com/juick/service/MessagesService.java b/src/main/java/com/juick/service/MessagesService.java
index 4bcdba46..922170db 100644
--- a/src/main/java/com/juick/service/MessagesService.java
+++ b/src/main/java/com/juick/service/MessagesService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2017, Juick
+ * Copyright (C) 2008-2019, Juick
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -29,7 +29,7 @@ import java.util.*;
* Created by aalexeev on 11/13/16.
*/
public interface MessagesService {
- int createMessage(int uid, String txt, String attachment, Collection<com.juick.Tag> tags);
+ int createMessage(int uid, String txt, String attachment, List<com.juick.Tag> tags);
int createReply(int mid, int rid, User user, String txt, String attachment);
@@ -68,7 +68,7 @@ public interface MessagesService {
User getMessageAuthor(int mid);
- List<String> getMessageRecommendations(int mid);
+ List<User> getMessageRecommendations(int mid);
List<Integer> getAll(int visitorUid, int before);
diff --git a/src/main/java/com/juick/service/MessagesServiceImpl.java b/src/main/java/com/juick/service/MessagesServiceImpl.java
index 4e5dca81..7dbfe1dd 100644
--- a/src/main/java/com/juick/service/MessagesServiceImpl.java
+++ b/src/main/java/com/juick/service/MessagesServiceImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2017, Juick
+ * Copyright (C) 2008-2019, Juick
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -17,11 +17,14 @@
package com.juick.service;
-import com.juick.*;
+import com.juick.Message;
+import com.juick.Reaction;
+import com.juick.User;
import com.juick.model.AnonymousUser;
import com.juick.model.PrivacyOpts;
import com.juick.model.ResponseReply;
import com.juick.server.util.HttpNotFoundException;
+import com.juick.server.www.WebApp;
import com.juick.util.MessageUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@@ -29,6 +32,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
@@ -37,12 +41,24 @@ import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
+import javax.annotation.Nonnull;
import javax.inject.Inject;
import java.net.URI;
-import java.sql.*;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
import java.time.Instant;
-import java.util.*;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -59,6 +75,8 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
private SearchService searchService;
@Inject
private ImagesService imagesService;
+ @Inject
+ private WebApp webApp;
@Value("${photos_url:https://i.juick.com/}")
private String baseImagesUrl;
@@ -75,7 +93,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
user.setBanned(rs.getBoolean(6));
user.setUri(URI.create(Optional.ofNullable(rs.getString(22)).orElse(StringUtils.EMPTY)));
msg.setUser(user);
- msg.setTimestamp(rs.getTimestamp(7).toInstant());
+ msg.setCreated(rs.getTimestamp(7).toInstant());
msg.ReadOnly = rs.getBoolean(8);
msg.setPrivacy(rs.getInt(9));
msg.FriendsOnly = msg.getPrivacy() < 0;
@@ -83,7 +101,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
msg.setAttachmentType(rs.getString(11));
msg.setLikes(rs.getInt(12));
msg.Hidden = rs.getBoolean(13);
- String tagsStr = rs.getString(14);
+ String tagsStr = StringUtils.defaultString(rs.getString(14));
msg.setTags(MessageUtils.parseTags(tagsStr));
msg.setRepliesBy(rs.getString(15));
msg.setText(rs.getString(16));
@@ -96,6 +114,8 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
if (quoteUid == 0) {
quoteUser.setName(AnonymousUser.INSTANCE.getName());
quoteUser.setUri(URI.create(Optional.ofNullable(rs.getString(23)).orElse(StringUtils.EMPTY)));
+ } else {
+ quoteUser.setAvatar(webApp.getAvatarUrl(quoteUser));
}
msg.setTo(quoteUser);
msg.setUpdatedAt(rs.getTimestamp(21).toInstant());
@@ -119,7 +139,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
*/
@Transactional
@Override
- public int createMessage(final int uid, final String txt, final String attachment, final Collection<com.juick.Tag> tags) {
+ public int createMessage(final int uid, final String txt, final String attachment, final List<com.juick.Tag> tags) {
SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(getJdbcTemplate()).withTableName("messages")
.usingColumns("user_id", "attach", "ts")
.usingGeneratedKeyColumns("message_id");
@@ -132,34 +152,25 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
}
int mid = simpleJdbcInsert.executeAndReturnKey(insertMap).intValue();
if (mid > 0) {
- String tagsNames = StringUtils.EMPTY;
-
if (CollectionUtils.isNotEmpty(tags)) {
- StringBuilder tasNamesBuilder = new StringBuilder();
- List<Object[]> params = new ArrayList<>(tags.size());
-
- boolean next = false;
-
- for (Tag tag : tags) {
- if (next) {
- tasNamesBuilder.append(" ");
- } else
- next = true;
-
- tasNamesBuilder.append(tag.getName());
- params.add(new Object[]{mid, tag.TID});
- }
- tagsNames = tasNamesBuilder.toString();
-
getJdbcTemplate().batchUpdate(
"INSERT INTO messages_tags(message_id, tag_id) VALUES (?, ?)",
- params, new int[]{Types.INTEGER, Types.INTEGER});
+ new BatchPreparedStatementSetter() {
+ @Override
+ public void setValues(@Nonnull PreparedStatement ps, int i) throws SQLException {
+ ps.setInt(1, mid);
+ ps.setInt(2, tags.get(i).TID);
+ }
+ @Override
+ public int getBatchSize() {
+ return tags.size();
+ }
+ });
}
-
getJdbcTemplate().update(
- "INSERT INTO messages_txt(message_id, tags, txt, updated_at) VALUES (?, ?, ?, ?)",
- new Object[]{mid, tagsNames, txt, Timestamp.from(now)},
- new int[]{Types.INTEGER, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP});
+ "INSERT INTO messages_txt(message_id, txt, updated_at) VALUES (?, ?, ?)",
+ new Object[]{mid, txt, Timestamp.from(now)},
+ new int[]{Types.INTEGER, Types.VARCHAR, Types.TIMESTAMP});
getJdbcTemplate().update("UPDATE users SET lastmessage=?, last_seen=? where id=?", Timestamp.from(now), Timestamp.from(now), uid);
}
@@ -365,16 +376,18 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
+ "messages.ts,"
+ "messages.readonly, messages.privacy, messages.replies,"
+ "messages.attach, COUNT(DISTINCT favorites.user_id) as likes, messages.hidden,"
- + "txt.tags, txt.repliesby, txt.txt, '' as q, messages.updated as updated, 0 as to_uid, "
+ + "GROUP_CONCAT(tags.name SEPARATOR ' '), txt.repliesby, txt.txt, '' as q, messages.updated as updated, 0 as to_uid, "
+ "NULL as to_name, txt.updated_at, '' as user_uri, '' as to_uri, '' as reply_uri, 0 as html FROM messages "
+ "INNER JOIN users ON messages.user_id = users.id "
+ "INNER JOIN messages_txt AS txt "
+ "ON messages.message_id = txt.message_id "
+ "LEFT JOIN favorites "
+ "ON messages.message_id = favorites.message_id AND favorites.like_id=1 "
+ + "LEFT JOIN messages_tags ON messages_tags.message_id=txt.message_id "
+ + "LEFT JOIN tags ON tags.tag_id=messages_tags.tag_id "
+ "WHERE messages.message_id = ? "
+ "GROUP BY mid, rid, replyto, uid, nick, banned, messages.ts, readonly, "
- + "privacy, replies, attach, tags, repliesby, q, updated_at, user_uri, to_uri, reply_uri, html",
+ + "privacy, replies, attach, repliesby, q, updated_at, user_uri, to_uri, reply_uri, html",
new MessageMapper(),
mid);
if (!list.isEmpty()) {
@@ -418,7 +431,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
URI.create(Optional.ofNullable(rs.getString(11)).orElse(StringUtils.EMPTY)));
}
msg.setReplyto(rs.getInt(3));
- msg.setTimestamp(rs.getTimestamp(4).toInstant());
+ msg.setCreated(rs.getTimestamp(4).toInstant());
msg.setAttachmentType(rs.getString(5));
msg.setText(rs.getString(6));
String quote = rs.getString(7);
@@ -477,15 +490,21 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
@Transactional(readOnly = true)
@Override
- public List<String> getMessageRecommendations(final int mid) {
- return getJdbcTemplate().queryForList(
- "SELECT DISTINCT users.nick FROM favorites " +
+ public List<User> getMessageRecommendations(final int mid) {
+ return getJdbcTemplate().query(
+ "SELECT DISTINCT users.id, users.nick, favorites.user_uri FROM favorites " +
"INNER JOIN users ON (favorites.message_id = ? AND favorites.user_id = users.id) " +
"INNER JOIN messages m ON favorites.message_id=m.message_id WHERE favorites.like_id=1 " +
"AND NOT EXISTS (SELECT 1 FROM bl_users WHERE " +
"(user_id = favorites.user_id AND bl_user_id = m.user_id) " +
"OR (user_id = m.user_id AND bl_user_id = favorites.user_id))",
- String.class, mid);
+ (rs, rowNum) -> {
+ User user = new User();
+ user.setUid(rs.getInt(1));
+ user.setName(rs.getString(2));
+ user.setUri(URI.create(rs.getString(3)));
+ return user;
+ }, mid);
}
@Transactional(readOnly = true)
@@ -577,29 +596,25 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
.addValue("before", before);
List<Integer> mids = getNamedParameterJdbcTemplate().queryForList(
- "(SELECT message_id FROM messages " +
- " INNER JOIN subscr_users ON (subscr_users.suser_id = :uid AND subscr_users.user_id = messages.user_id) " +
- " WHERE " +
- (before > 0 ?
- " message_id < :before AND " : StringUtils.EMPTY) +
- " (privacy >= 0 OR (privacy >= -2 AND privacy <= -1" +
- " AND EXISTS (SELECT 1 FROM wl_users w WHERE w.wl_user_id = :uid and w.user_id = messages.user_id))) " +
- " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " +
- "(SELECT tag_id FROM messages_tags WHERE message_id = messages.message_id) and :uid = bt.user_id))" +
- " UNION " +
- " (SELECT message_id FROM messages WHERE user_id=:uid " +
- (before > 0 ?
- " AND message_id < :before " : StringUtils.EMPTY) +
+ "SELECT message_id FROM messages WHERE " +
+ "(user_id=:uid OR " +
+ "(EXISTS (SELECT 1 FROM subscr_users WHERE subscr_users.suser_id = :uid " +
+ "AND subscr_users.user_id = messages.user_id) " +
+ "AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " +
+ "(SELECT tag_id FROM messages_tags WHERE message_id = messages.message_id) AND :uid = bt.user_id) " +
+ "AND (privacy >= 0 OR (privacy >= -2 AND privacy <= -1 " +
+ "AND EXISTS (SELECT 1 FROM wl_users w WHERE w.wl_user_id = :uid and w.user_id = messages.user_id)))) " +
(recommended ?
- ") UNION " +
- " (SELECT f.message_id as message_id FROM favorites f INNER JOIN messages ON " +
- "f.message_id=messages.message_id WHERE " +
- "EXISTS (SELECT 1 FROM subscr_users s WHERE s.suser_id = :uid and f.user_id = s.user_id)" +
- (before > 0 ?
- " AND f.message_id < :before " : StringUtils.EMPTY) : StringUtils.EMPTY) +
- " AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid and b.bl_user_id = messages.user_id)" +
- " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " +
- "(SELECT tag_id FROM messages_tags WHERE message_id = messages.message_id) and :uid = bt.user_id)) " +
+ "OR (EXISTS (SELECT 1 FROM favorites WHERE favorites.message_id=messages.message_id " +
+ "AND favorites.user_id IN (SELECT user_id FROM subscr_users WHERE suser_id=:uid)) " +
+ "AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN (SELECT tag_id FROM messages_tags " +
+ "WHERE message_id = messages.message_id) and :uid = bt.user_id) " +
+ "AND (privacy >= 0 OR (privacy >= -2 AND privacy <= -1 " +
+ "AND EXISTS (SELECT 1 FROM wl_users w " +
+ "WHERE w.wl_user_id = :uid and w.user_id = messages.user_id)))) " +
+ "AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid and b.bl_user_id = messages.user_id)" : StringUtils.EMPTY) +
+ ") " +
+ (before > 0 ? "AND message_id < :before " : StringUtils.EMPTY) +
"ORDER BY message_id DESC LIMIT 20",
sqlParameterSource,
Integer.class);
@@ -871,7 +886,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
+ "messages.ts,"
+ "messages.readonly,messages.privacy, messages.replies-COUNT(DISTINCT banned.reply_id) as replies,"
+ "messages.attach,COUNT(DISTINCT favorites.user_id) AS likes,messages.hidden,"
- + "messages_txt.tags,messages_txt.repliesby, messages_txt.txt, '' as q, "
+ + "GROUP_CONCAT(tags.name SEPARATOR ' '), messages_txt.repliesby, messages_txt.txt, '' as q, "
+ "messages.updated, 0 as to_uid, NULL as to_name, messages_txt.updated_at, '' as m_user_uri, "
+ "'' as to_uri, '' as msg_reply_uri, 0 as html "
+ "FROM (messages INNER JOIN messages_txt "
@@ -881,9 +896,11 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
+ "ON messages.message_id = favorites.message_id AND favorites.like_id=1 "
+ "LEFT JOIN banned "
+ "ON messages.message_id = banned.message_id "
+ + "LEFT JOIN messages_tags ON messages_tags.message_id=messages_txt.message_id "
+ + "LEFT JOIN tags ON tags.tag_id=messages_tags.tag_id "
+ "WHERE messages.message_id IN (:ids) GROUP BY "
+ "messages.message_id, rid, replyto, messages.user_id, users.nick, usr_banned, messages.ts, "
- + "messages.readonly, messages.privacy, messages.attach, messages.hidden, messages_txt.tags, "
+ + "messages.readonly, messages.privacy, messages.attach, messages.hidden, "
+ "messages_txt.repliesby, messages_txt.txt, q, messages.updated, to_uid, to_name, updated_at, "
+ "m_user_uri, msg_reply_uri, html",
new MapSqlParameterSource("ids", mids)
@@ -971,7 +988,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
"ORDER BY replies.reply_id ASC",
new MapSqlParameterSource("mid", mid).addValue("uid", user.getUid()),
new MessageMapper());
- if (replies.size() > 0) {
+ if (replies.size() > 0 && !user.isAnonymous()) {
setRead(user, mid);
}
replies.forEach(i -> i.setEntities(MessageUtils.getEntities(i)));
@@ -1143,7 +1160,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
@Override
public boolean updateReplyUri(Message reply, URI replyUri) {
- return jdbcTemplate.update("UPDATE replies SET reply_uri=?, html=1 WHERE message_id=? AND reply_id=?",
+ return jdbcTemplate.update("UPDATE replies SET reply_uri=?, html=0 WHERE message_id=? AND reply_id=?",
replyUri.toASCIIString(), reply.getMid(), reply.getRid()) > 0;
}
diff --git a/src/main/java/com/juick/service/PMQueriesServiceImpl.java b/src/main/java/com/juick/service/PMQueriesServiceImpl.java
index 712e4b0e..f1f98024 100644
--- a/src/main/java/com/juick/service/PMQueriesServiceImpl.java
+++ b/src/main/java/com/juick/service/PMQueriesServiceImpl.java
@@ -105,7 +105,7 @@ public class PMQueriesServiceImpl extends BaseJdbcService implements PMQueriesSe
user.setName(rs.getString(4));
msg.setUser(user);
msg.setText(rs.getString(2).trim());
- msg.setTimestamp(rs.getTimestamp(3).toInstant());
+ msg.setCreated(rs.getTimestamp(3).toInstant());
return msg;
});
}
@@ -122,7 +122,7 @@ public class PMQueriesServiceImpl extends BaseJdbcService implements PMQueriesSe
msg.getUser().setUid(rs.getInt(1));
msg.getUser().setName(rs.getString(2));
msg.setText(rs.getString(3).trim());
- msg.setTimestamp(rs.getTimestamp(4).toInstant());
+ msg.setCreated(rs.getTimestamp(4).toInstant());
return msg;
},
uid);
@@ -141,7 +141,7 @@ public class PMQueriesServiceImpl extends BaseJdbcService implements PMQueriesSe
msg.getUser().setUid(rs.getInt(1));
msg.getUser().setName(rs.getString(2));
msg.setText(rs.getString(3).trim());
- msg.setTimestamp(rs.getTimestamp(4).toInstant());
+ msg.setCreated(rs.getTimestamp(4).toInstant());
return msg;
},
uid);
diff --git a/src/main/java/com/juick/service/TagServiceImpl.java b/src/main/java/com/juick/service/TagServiceImpl.java
index 42159d3b..95a1a309 100644
--- a/src/main/java/com/juick/service/TagServiceImpl.java
+++ b/src/main/java/com/juick/service/TagServiceImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2017, Juick
+ * Copyright (C) 2008-2019, Juick
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -20,10 +20,10 @@ package com.juick.service;
import com.juick.Tag;
import com.juick.User;
import com.juick.model.TagStats;
-import com.juick.util.StreamUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
@@ -31,6 +31,7 @@ import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
+import javax.annotation.Nonnull;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -199,21 +200,28 @@ public class TagServiceImpl extends BaseJdbcService implements TagService {
"DELETE FROM messages_tags WHERE message_id = :mid AND tag_id in (:ids)",
new MapSqlParameterSource().addValue("ids", idsForDelete).addValue("mid", mid));
- newTags.stream().filter(t -> !currentTags.contains(t))
- .forEach(t -> getJdbcTemplate().update("INSERT INTO messages_tags(message_id,tag_id) VALUES (?,?)", mid, t.TID));
-
- List<Tag> result = getMessageTags(mid).stream()
+ List<Tag> addedTags = newTags.stream().filter(t -> !currentTags.contains(t)).collect(Collectors.toList());
+ getJdbcTemplate().batchUpdate("INSERT INTO messages_tags(message_id,tag_id) VALUES (?,?)", new BatchPreparedStatementSetter() {
+ @Override
+ public void setValues(@Nonnull PreparedStatement ps, int i) throws SQLException {
+ ps.setInt(1, mid);
+ ps.setInt(2, addedTags.get(i).TID);
+ }
+ @Override
+ public int getBatchSize() {
+ return addedTags.size();
+ }
+ });
+
+ return getMessageTags(mid).stream()
.map(TagStats::getTag).collect(Collectors.toList());
- jdbcTemplate.update("UPDATE messages_txt SET tags=? WHERE message_id=?", result.stream()
- .map(Tag::getName).collect(Collectors.joining(" ")), mid);
- return result;
}
@Override
public Pair<String, List<Tag>> fromString(final String txt) {
String firstLine = txt.split("\\n", 2)[0];
- Supplier<Stream<String>> tagsStream = () -> StreamUtils.takeWhile(Arrays.stream(firstLine.split("\\ ")),
- t -> !t.equals("*") && t.startsWith("*"));
+ Supplier<Stream<String>> tagsStream = () -> Arrays.stream(firstLine.split("\\ "))
+ .takeWhile(t -> !t.equals("*") && t.startsWith("*"));
int tagsLength = tagsStream.get().collect(Collectors.joining(" ")).length();
String body = txt.substring(tagsLength);
List<Tag> tags = tagsStream.get().map(t -> getTag(t.substring(1), true))
diff --git a/src/main/java/com/juick/service/UserService.java b/src/main/java/com/juick/service/UserService.java
index 832f978a..3a51dffb 100644
--- a/src/main/java/com/juick/service/UserService.java
+++ b/src/main/java/com/juick/service/UserService.java
@@ -20,7 +20,6 @@ package com.juick.service;
import com.juick.Message;
import com.juick.User;
import com.juick.model.Auth;
-import com.juick.model.UserInfo;
import javax.annotation.Nonnull;
import java.time.Instant;
@@ -75,9 +74,9 @@ public interface UserService {
int setUserOptionInt(int uid, String option, int value);
- UserInfo getUserInfo(User user);
+ User getUserInfo(User user);
- boolean updateUserInfo(User user, UserInfo info);
+ boolean updateUserInfo(User info);
boolean getCanMedia(int uid);
diff --git a/src/main/java/com/juick/service/UserServiceImpl.java b/src/main/java/com/juick/service/UserServiceImpl.java
index 93904139..bcfb8dac 100644
--- a/src/main/java/com/juick/service/UserServiceImpl.java
+++ b/src/main/java/com/juick/service/UserServiceImpl.java
@@ -21,7 +21,6 @@ import com.juick.Message;
import com.juick.User;
import com.juick.model.AnonymousUser;
import com.juick.model.Auth;
-import com.juick.model.UserInfo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
@@ -121,7 +120,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService {
return -1;
}
- int uid = holder.getKey().intValue();
+ int uid = holder.getKeys().size() > 1 ? (int)holder.getKeys().get("id") : holder.getKey().intValue();
getJdbcTemplate().update("INSERT INTO useroptions(user_id) VALUES (?)", uid);
getJdbcTemplate().update("INSERT INTO subscr_users(user_id, suser_id) VALUES (2, ?)", uid);
@@ -133,7 +132,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService {
@Override
public Optional<User> getUserByUID(final int uid) {
List<User> list = getJdbcTemplate().query(
- "SELECT u.id, u.nick, u.passw, u.banned, u.last_seen, " +
+ "SELECT DISTINCT u.id, u.nick, u.passw, u.banned, u.last_seen, " +
"COALESCE(f.fb_id, vk.vk_id, t.tg_id, e.user_id, 0) AS verified " +
"FROM users u LEFT JOIN facebook f ON f.user_id = u.id " +
"LEFT JOIN vk ON u.id = vk.user_id LEFT JOIN telegram t ON u.id = t.user_id " +
@@ -148,7 +147,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService {
public User getUserByName(final String username) {
if (StringUtils.isNotBlank(username)) {
List<User> list = getJdbcTemplate().query(
- "SELECT u.id, u.nick, u.passw, u.banned, u.last_seen, " +
+ "SELECT DISTINCT u.id, u.nick, u.passw, u.banned, u.last_seen, " +
"COALESCE(f.fb_id, vk.vk_id, t.tg_id, e.user_id, 0) AS verified " +
"FROM users u LEFT JOIN facebook f ON f.user_id = u.id " +
"LEFT JOIN vk ON u.id = vk.user_id LEFT JOIN telegram t ON u.id = t.user_id " +
@@ -167,7 +166,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService {
public User getUserByEmail(String email) {
if (StringUtils.isNotBlank(email)) {
List<User> list = getJdbcTemplate().query(
- "SELECT u.id, u.nick, u.passw, u.banned, u.last_seen, " +
+ "SELECT DISTINCT u.id, u.nick, u.passw, u.banned, u.last_seen, " +
"COALESCE(f.fb_id, vk.vk_id, t.tg_id, e.user_id, 0) AS verified " +
"FROM users u LEFT JOIN facebook f ON f.user_id = u.id " +
"LEFT JOIN vk ON u.id = vk.user_id LEFT JOIN telegram t ON u.id = t.user_id " +
@@ -189,7 +188,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService {
if (StringUtils.isNotBlank(jid)) {
List<User> list = getJdbcTemplate().query(
- "SELECT u.id, u.nick, u.passw, u.banned, u.last_seen," +
+ "SELECT DISTINCT u.id, u.nick, u.passw, u.banned, u.last_seen," +
"COALESCE(f.fb_id, vk.vk_id, t.tg_id, e.user_id, 0) AS verified " +
"FROM users u LEFT JOIN facebook f ON f.user_id = u.id " +
"LEFT JOIN vk ON u.id = vk.user_id LEFT JOIN telegram t ON u.id = t.user_id " +
@@ -211,7 +210,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService {
return Collections.emptyList();
return getNamedParameterJdbcTemplate().query(
- "SELECT u.id, u.nick, u.passw, u.banned, u.last_seen," +
+ "SELECT DISTINCT u.id, u.nick, u.passw, u.banned, u.last_seen," +
"COALESCE(f.fb_id, vk.vk_id, t.tg_id, e.user_id, 0) AS verified " +
"FROM users u LEFT JOIN facebook f ON f.user_id = u.id " +
"LEFT JOIN vk ON u.id = vk.user_id LEFT JOIN telegram t ON u.id = t.user_id " +
@@ -228,7 +227,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService {
return Collections.emptyList();
return getNamedParameterJdbcTemplate().query(
- "SELECT u.id, u.nick, u.passw, u.banned, u.last_seen," +
+ "SELECT DISTINCT u.id, u.nick, u.passw, u.banned, u.last_seen," +
"COALESCE(f.fb_id, vk.vk_id, t.tg_id, e.user_id, 0) AS verified " +
"FROM users u LEFT JOIN facebook f ON f.user_id = u.id " +
"LEFT JOIN vk ON u.id = vk.user_id LEFT JOIN telegram t ON u.id = t.user_id " +
@@ -288,7 +287,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService {
public com.juick.User getUserByHash(final String hash) {
if (StringUtils.isNotBlank(hash)) {
List<User> list = getJdbcTemplate().query(
- "SELECT logins.user_id, u.nick, u.passw, u.banned, u.last_seen," +
+ "SELECT DISTINCT logins.user_id, u.nick, u.passw, u.banned, u.last_seen," +
"COALESCE(f.fb_id, vk.vk_id, t.tg_id, e.user_id, 0) AS verified " +
"FROM logins INNER JOIN users u ON logins.user_id = u.id " +
"LEFT JOIN facebook f ON f.user_id = u.id " +
@@ -326,7 +325,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService {
public int checkPassword(final String username, final String password) {
if (StringUtils.isNotBlank(username)) {
List<User> list = getJdbcTemplate().query(
- "SELECT u.id, u.nick, u.passw, u.banned, u.last_seen," +
+ "SELECT DISTINCT u.id, u.nick, u.passw, u.banned, u.last_seen," +
"COALESCE(f.fb_id, vk.vk_id, t.tg_id, e.user_id, 0) AS verified " +
"FROM users u LEFT JOIN facebook f ON f.user_id = u.id " +
"LEFT JOIN vk ON u.id = vk.user_id LEFT JOIN telegram t ON u.id = t.user_id " +
@@ -375,29 +374,31 @@ public class UserServiceImpl extends BaseJdbcService implements UserService {
@Transactional(readOnly = true)
@Override
- public UserInfo getUserInfo(final User user) {
- List<UserInfo> list = getJdbcTemplate().query(
- "SELECT fullname, country, url, descr FROM usersinfo WHERE user_id = ?",
- ((rs, rowNum) -> {
- UserInfo info = new UserInfo();
- info.setFullName(rs.getString(1));
- info.setCountry(rs.getString(2));
- info.setUrl(rs.getString(3));
- info.setDescription(rs.getString(4));
- return info;
- }),
- user.getUid());
-
- return list.isEmpty() ? new UserInfo() : list.get(0);
+ public User getUserInfo(final User user) {
+ try {
+ getJdbcTemplate().queryForObject(
+ "SELECT fullname, country, url, descr FROM usersinfo WHERE user_id = ?",
+ ((rs, rowNum) -> {
+ user.setFullName(rs.getString(1));
+ user.setCountry(rs.getString(2));
+ user.setUrl(rs.getString(3));
+ user.setDescription(rs.getString(4));
+ return user;
+ }),
+ user.getUid());
+ } catch (EmptyResultDataAccessException e) {
+ return user;
+ }
+ return user;
}
@Transactional
@Override
- public boolean updateUserInfo(final User user, final UserInfo info) {
+ public boolean updateUserInfo(final User info) {
try {
return getJdbcTemplate().update(
"INSERT INTO usersinfo(user_id, fullname, country, url, descr) VALUES (?, ?, ?, ?, ?)",
- user.getUid(),
+ info.getUid(),
info.getFullName(),
info.getCountry(),
info.getUrl(),
@@ -408,7 +409,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService {
info.getCountry(),
info.getUrl(),
info.getDescription(),
- user.getUid()) > 0;
+ info.getUid()) > 0;
}
}
diff --git a/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java b/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java
new file mode 100644
index 00000000..44d97207
--- /dev/null
+++ b/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java
@@ -0,0 +1,71 @@
+package com.juick.service.security;
+
+import com.juick.User;
+import com.juick.server.SignatureManager;
+import com.juick.service.UserService;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.annotation.Nonnull;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class HTTPSignatureAuthenticationFilter extends OncePerRequestFilter {
+
+ private final SignatureManager signatureManager;
+ private final UserService userService;
+
+
+ public HTTPSignatureAuthenticationFilter(
+ final SignatureManager signatureManager,
+ final UserService userService) {
+ this.signatureManager = signatureManager;
+ this.userService = userService;
+ }
+ @Override
+ protected void doFilterInternal(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull FilterChain filterChain) throws IOException, ServletException {
+ if (authenticationIsRequired()) {
+ Map<String, String> headers = Collections.list(request.getHeaderNames())
+ .stream()
+ .collect(Collectors.toMap(String::toLowerCase, request::getHeader));
+ if (StringUtils.isNotEmpty(headers.get("signature"))) {
+ User user = signatureManager.verifySignature(request.getMethod(), request.getRequestURI(), headers);
+ String userUri = user.getUri().toString();
+ if (!user.isAnonymous() || userUri.length() > 0) {
+ if (userUri.length() == 0) {
+ User userWithPassword = userService.getUserByName(user.getName());
+ userWithPassword.setAuthHash(userService.getHashByUID(userWithPassword.getUid()));
+ Authentication authentication = new UsernamePasswordAuthenticationToken(userWithPassword.getName(), userWithPassword.getCredentials());
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ } else {
+ Authentication authentication = new AnonymousAuthenticationToken(userUri, user, Collections.singletonList(new SimpleGrantedAuthority("ROLE_ANONYMOUS")));
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ }
+ }
+ }
+ }
+
+ filterChain.doFilter(request, response);
+ }
+
+ private boolean authenticationIsRequired() {
+ Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
+
+ return existingAuth == null ||
+ !existingAuth.isAuthenticated() ||
+ existingAuth instanceof AnonymousAuthenticationToken;
+ }
+}
diff --git a/src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java b/src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java
index 9215d09a..2fd5a2a7 100644
--- a/src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java
+++ b/src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java
@@ -30,6 +30,7 @@ import org.springframework.util.Assert;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.WebUtils;
+import javax.annotation.Nonnull;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
@@ -59,9 +60,9 @@ public class HashParamAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(
- HttpServletRequest request,
- HttpServletResponse response,
- FilterChain filterChain) throws ServletException, IOException {
+ @Nonnull HttpServletRequest request,
+ @Nonnull HttpServletResponse response,
+ @Nonnull FilterChain filterChain) throws ServletException, IOException {
String hash = getHashFromRequest(request);
diff --git a/src/main/java/com/juick/util/MessageUtils.java b/src/main/java/com/juick/util/MessageUtils.java
index cc0d7b12..fa94e978 100644
--- a/src/main/java/com/juick/util/MessageUtils.java
+++ b/src/main/java/com/juick/util/MessageUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2017, Juick
+ * Copyright (C) 2008-2019, Juick
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -28,7 +28,13 @@ import org.springframework.web.util.UriComponentsBuilder;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -87,36 +93,36 @@ public class MessageUtils {
private final static String underlineRegex = "((?<=\\s)|(?<=\\A))_([^\\_\\n<>]+)_((?=\\s)|(?=\\Z)|(?=\\p{Punct}))";
- private final static String citateRegex = "(?:(?<=\\n)|(?<=\\A))\\> *(.*)?(\\n|(?=\\Z))";
+ private final static String citateRegex = "(?:(?<=\\n)|(?<=\\A))(?:&gt;|>) *(.*)?(\\n|(?=\\Z))";
public static List<Entity> getEntities(Message msg) {
String txt = msg.getText();
// http://juick.com/last?page=2
- List<Entity> result = new ArrayList<>(entitiesForType("a", txt, urlWithWhitespacesRegex, matcher -> matcher.group(3), matcher -> Optional.of(matcher.group(2))));
+ List<Entity> result = new ArrayList<>(entitiesForType("a", txt, urlWithWhitespacesRegex, matcher -> matcher.group(3), matcher -> Optional.of(matcher.group(2)), 0));
// [link text][http://juick.com/last?page=2]
- result.addAll(entitiesForType("a", txt, textUrlRegex, matcher -> matcher.group(1), matcher -> Optional.of(matcher.group(2))));
+ result.addAll(entitiesForType("a", txt, textUrlRegex, matcher -> matcher.group(1), matcher -> Optional.of(matcher.group(2)), 0));
// [link text](http://juick.com/last?page=2)
- result.addAll(entitiesForType("a", txt, textUrlRegex2, matcher -> matcher.group(1), matcher -> Optional.of(matcher.group(2))));
+ result.addAll(entitiesForType("a", txt, textUrlRegex2, matcher -> matcher.group(1), matcher -> Optional.of(matcher.group(2)), 0));
// #12345
- result.addAll(entitiesForType("a", txt, midRegex, matcher -> String.format("#%s", matcher.group(2)), matcher -> Optional.of("https://juick.com/m/" + matcher.group(2))));
+ result.addAll(entitiesForType("a", txt, midRegex, matcher -> String.format("#%s", matcher.group(2)), matcher -> Optional.of("https://juick.com/m/" + matcher.group(2)), 0));
// #12345/65
- result.addAll(entitiesForType("a", txt, ridRegex, matcher -> String.format("#%s/%s", matcher.group(2), matcher.group(3)), matcher -> Optional.of(String.format("https://juick.com/m/%s#%s", matcher.group(2), matcher.group(3)))));
+ result.addAll(entitiesForType("a", txt, ridRegex, matcher -> String.format("#%s/%s", matcher.group(2), matcher.group(3)), matcher -> Optional.of(String.format("https://juick.com/m/%s#%s", matcher.group(2), matcher.group(3))), 0));
// /12
- result.addAll(entitiesForType("a", txt, replyNumberRegex, matcher -> "/" + matcher.group(2), matcher -> Optional.of(String.format("https://juick.com/m/%d#%s", msg.getMid(), matcher.group(2)))));
+ result.addAll(entitiesForType("a", txt, replyNumberRegex, matcher -> "/" + matcher.group(2), matcher -> Optional.of(String.format("https://juick.com/m/%d#%s", msg.getMid(), matcher.group(2))), 0));
// @username@jabber.org
- result.addAll(entitiesForType("a", txt, jidRegex, matcher -> matcher.group(2), matcher -> Optional.of(String.format("https://juick.com/%s", matcher.group(2)))));
+ result.addAll(entitiesForType("a", txt, jidRegex, matcher -> matcher.group(2), matcher -> Optional.of(String.format("https://juick.com/%s", matcher.group(2))), 0));
// @username
- result.addAll(entitiesForType("a", txt, usernameRegex, matcher -> matcher.group(2), matcher -> Optional.of(String.format("https://juick.com/%s", matcher.group(2)))));
+ result.addAll(entitiesForType("a", txt, usernameRegex, matcher -> matcher.group(2), matcher -> Optional.of(String.format("https://juick.com/%s", matcher.group(2))), 0));
// *bold*
- result.addAll(entitiesForType("b", txt, boldRegex, matcher -> matcher.group(2), matcher -> Optional.empty()));
+ result.addAll(entitiesForType("b", txt, boldRegex, matcher -> matcher.group(2), matcher -> Optional.empty(), 0));
// /italic/
- result.addAll(entitiesForType("i", txt, italicRegex, matcher -> matcher.group(2), matcher -> Optional.empty()));
+ result.addAll(entitiesForType("i", txt, italicRegex, matcher -> matcher.group(2), matcher -> Optional.empty(), 0));
// _underline_
- result.addAll(entitiesForType("u", txt, underlineRegex, matcher -> matcher.group(2), matcher -> Optional.empty()));
+ result.addAll(entitiesForType("u", txt, underlineRegex, matcher -> matcher.group(2), matcher -> Optional.empty(), 0));
// > citate
- result.addAll(entitiesForType("q", txt, citateRegex, matcher -> matcher.group(1), matcher -> Optional.empty()));
+ result.addAll(entitiesForType("q", txt, citateRegex, matcher -> matcher.group(1), matcher -> Optional.empty(), 1));
return result;
}
@@ -144,6 +150,11 @@ public class MessageUtils {
}
public static String formatMessage(String msg) {
+
+ msg = msg.replaceAll("&", "&amp;");
+ msg = msg.replaceAll("<", "&lt;");
+ msg = msg.replaceAll(">", "&gt;");
+
// --
// &mdash;
msg = msg.replaceAll("((?<=\\s)|(?<=\\A))\\-\\-?((?=\\s)|(?=\\Z))", "$1&mdash;$2");
@@ -294,23 +305,15 @@ public class MessageUtils {
public static boolean replyStartsWithQuote(Message msg) {
return msg.getRid() > 0 && StringUtils.defaultString(msg.getText()).startsWith(">");
}
- public static List<Tag> parseTags(String strTags) {
- List<Tag> tags = new ArrayList<>();
- if (StringUtils.isNotEmpty(strTags)) {
- Set<Tag> tagSet = new TreeSet<>(tags);
- for (String str : strTags.split(" ")) {
- Tag tag = new Tag(str);
- if (!tagSet.contains(tag)) {
- tags.add(tag);
- tagSet.add(tag);
- }
- }
- }
- return tags;
+ public static Set<Tag> parseTags(String strTags) {
+ return StringUtils.isEmpty(strTags) ? Collections.emptySet()
+ : Arrays.stream(strTags.split(" ")).map(Tag::new)
+ .collect(Collectors.toCollection(LinkedHashSet::new));
}
public static String getTagsString(Message msg) {
StringBuilder builder = new StringBuilder();
- List<Tag> tags = msg.getTags();
+ Set<Tag> tags = msg.getTags();
+
if (!tags.isEmpty()) {
for (Tag Tag : tags)
builder.append(" *").append(Tag.getName());
@@ -369,7 +372,20 @@ public class MessageUtils {
return collectMatches(jidPattern, msg.getText());
}
- private static List<Entity> entitiesForType(String type, String input, String patternText, Function<Matcher, String> textGroup, Function<Matcher, Optional<String>> linkGroup) {
+ /**
+ *
+ * @param type Name of the entity
+ * @param input data to find matches
+ * @param patternText pattern to match
+ * @param textGroup function which return text representation
+ * @param linkGroup function which return link address
+ * @param endGroupId group id used to set end of entity (e.g. do not count linebreak as part of quote entity)
+ * @return list of entities
+ */
+ private static List<Entity> entitiesForType(String type, String input, String patternText,
+ Function<Matcher, String> textGroup,
+ Function<Matcher, Optional<String>> linkGroup,
+ int endGroupId) {
List<Entity> result = new ArrayList<>();
Pattern pattern = Pattern.compile(patternText);
Matcher matcher = pattern.matcher(input);
@@ -380,7 +396,7 @@ public class MessageUtils {
Optional<String> link = linkGroup.apply(matcher);
link.ifPresent(entity::setUrl);
entity.setStart(matcher.start());
- entity.setEnd(matcher.end());
+ entity.setEnd(matcher.end(endGroupId));
result.add(entity);
}
return result;
diff --git a/src/main/java/com/juick/util/StreamUtils.java b/src/main/java/com/juick/util/StreamUtils.java
deleted file mode 100644
index 576107af..00000000
--- a/src/main/java/com/juick/util/StreamUtils.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.juick.util;
-
-import java.util.Spliterator;
-import java.util.Spliterators;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-/**
- * @deprecated switch to JDK9+ Stream API when possible
- */
-@Deprecated
-public class StreamUtils {
- private static <T> Spliterator<T> takeWhile(
- Spliterator<T> splitr, Predicate<? super T> predicate) {
- return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) {
- boolean stillGoing = true;
- @Override public boolean tryAdvance(Consumer<? super T> consumer) {
- if (stillGoing) {
- boolean hadNext = splitr.tryAdvance(elem -> {
- if (predicate.test(elem)) {
- consumer.accept(elem);
- } else {
- stillGoing = false;
- }
- });
- return hadNext && stillGoing;
- }
- return false;
- }
- };
- }
-
- public static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> predicate) {
- return StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false);
- }
-}
diff --git a/src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java b/src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java
index c7b00ea3..c83c3a45 100644
--- a/src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java
+++ b/src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2017, Juick
+ * Copyright (C) 2008-2019, Juick
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -22,6 +22,7 @@ import com.mitchellbosecke.pebble.extension.Filter;
import com.mitchellbosecke.pebble.template.EvaluationContext;
import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -33,7 +34,7 @@ public class TagsListFilter implements Filter {
@SuppressWarnings("unchecked")
@Override
public Object apply(Object input, Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {
- return ((List<Tag>) input).stream().map(Tag::getName).collect(Collectors.toList());
+ return ((Collection<Tag>) input).stream().map(Tag::getName).collect(Collectors.toList());
}
@Override
diff --git a/src/main/java/ru/sape/Sape.java b/src/main/java/ru/sape/Sape.java
index 38577c45..a94bcc62 100644
--- a/src/main/java/ru/sape/Sape.java
+++ b/src/main/java/ru/sape/Sape.java
@@ -3,6 +3,8 @@
*/
package ru.sape;
+import java.net.URI;
+
public class Sape {
private final String sapeUser;
@@ -17,7 +19,7 @@ public class Sape {
}
public boolean debug = false;
- public SapePageLinks getPageLinks(String requestUri, String cookie) {
+ public SapePageLinks getPageLinks(URI requestUri, String cookie) {
return new SapePageLinks(sapePageLinkConnection, sapeUser, requestUri, cookie, debug);
}
}
diff --git a/src/main/java/ru/sape/SapePageLinks.java b/src/main/java/ru/sape/SapePageLinks.java
index e89b4e71..77715aea 100644
--- a/src/main/java/ru/sape/SapePageLinks.java
+++ b/src/main/java/ru/sape/SapePageLinks.java
@@ -1,17 +1,18 @@
package ru.sape;
+import org.apache.commons.lang3.StringUtils;
+
+import java.net.URI;
import java.util.*;
public class SapePageLinks {
private boolean showCode;
- public SapePageLinks(SapeConnection sapeConnection, String sapeUser, String requestUri, String sapeCookie) {
- this(sapeConnection, sapeUser, requestUri, sapeCookie, false);
- }
-
@SuppressWarnings("unchecked")
- public SapePageLinks(SapeConnection sapeConnection, String sapeUser, String requestUri, String sapeCookie, boolean showCode) {
+ public SapePageLinks(SapeConnection sapeConnection, String sapeUser, URI request, String sapeCookie, boolean showCode) {
+ String req = StringUtils.isNotEmpty(request.getQuery()) ? request.getPath() + "?" + request.getQuery()
+ : request.getPath();
if (sapeUser.equals(sapeCookie)) {
showCode = true;
}
@@ -22,8 +23,8 @@ public class SapePageLinks {
linkDelimiter = (String) data.get("__sape_delimiter__");
}
- if (data.containsKey(requestUri)) {
- pageLinks = new ArrayList<>(((Map<Object, String>) data.get(requestUri)).values());
+ if (data.containsKey(req)) {
+ pageLinks = new ArrayList<>(((Map<Object, String>) data.get(req)).values());
}
if (data.containsKey("__sape_new_url__")) {
diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt
new file mode 100644
index 00000000..c81c89f7
--- /dev/null
+++ b/src/main/resources/banner.txt
@@ -0,0 +1,13 @@
+${AnsiColor.BRIGHT_RED}
+ ___ ___ ___ ___
+ /\ \ /\__\ ___ /\ \ /\__\
+ \:\ \ /:/ / /\ \ /::\ \ /:/ /
+ ___ /::\__\ /:/ / \:\ \ /:/\:\ \ /:/__/
+ /\ /:/\/__/ /:/ / ___ /::\__\ /:/ \:\ \ /::\__\____
+ \:\/:/ / /:/__/ /\__\ __/:/\/__/ /:/__/ \:\__\ /:/\:::::\__\
+ \::/ / \:\ \ /:/ / /\/:/ / \:\ \ \/__/ \/_|:|~~|~
+ \/__/ \:\ /:/ / \::/__/ \:\ \ |:| |
+ \:\/:/ / \:\__\ \:\ \ |:| |
+ \::/ / \/__/ \:\__\ |:| |
+ \/__/ \/__/ \|__|
+${AnsiColor.DEFAULT}
diff --git a/src/main/resources/db/migration/V1.17__drop tags column.sql b/src/main/resources/db/migration/V1.17__drop tags column.sql
new file mode 100644
index 00000000..ebb2d9a6
--- /dev/null
+++ b/src/main/resources/db/migration/V1.17__drop tags column.sql
@@ -0,0 +1 @@
+ALTER TABLE messages_txt DROP COLUMN tags; \ No newline at end of file
diff --git a/src/main/resources/db/migration/V1.18__increase messages and replies timestamp precision.sql b/src/main/resources/db/migration/V1.18__increase messages and replies timestamp precision.sql
new file mode 100644
index 00000000..5b298c46
--- /dev/null
+++ b/src/main/resources/db/migration/V1.18__increase messages and replies timestamp precision.sql
@@ -0,0 +1,5 @@
+ALTER TABLE replies MODIFY COLUMN ts timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP;
+ALTER TABLE messages MODIFY COLUMN ts timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP;
+ALTER TABLE messages MODIFY COLUMN updated timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP;
+ALTER TABLE messages_txt MODIFY COLUMN updated_at timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP;
+ALTER TABLE users MODIFY COLUMN lastmessage timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP;
diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql
index 2e8fad9b..423fc375 100644
--- a/src/main/resources/schema.sql
+++ b/src/main/resources/schema.sql
@@ -258,7 +258,7 @@ CREATE TABLE IF NOT EXISTS `useroptions` (
);
CREATE TABLE IF NOT EXISTS `users` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT(0),
`nick` char(64) NOT NULL,
`passw` char(32) NOT NULL,
`lang` enum('en','ru','fr','fa','__') NOT NULL DEFAULT '__',
diff --git a/src/main/resources/templates/layouts/note.html b/src/main/resources/templates/layouts/note.html
index 42b939c0..e832dc63 100644
--- a/src/main/resources/templates/layouts/note.html
+++ b/src/main/resources/templates/layouts/note.html
@@ -1,5 +1,5 @@
{% import "views/macros/tags" %}
<p>{{ msg | formatMessage }}</p>
-{% if msg.tags.size > 0 %}
+{% if msg.tags | length > 0 %}
<div class="msg-tags">{{ allTags(baseUri, msg.tags | tagsList) }}</div>
{% endif %} \ No newline at end of file
diff --git a/src/main/resources/templates/views/login.html b/src/main/resources/templates/views/login.html
index a538cb26..11900c8d 100644
--- a/src/main/resources/templates/views/login.html
+++ b/src/main/resources/templates/views/login.html
@@ -117,7 +117,7 @@
<li><a href="/tag/учеба" style="left: 616px; top: 84px; width: 43px; height: 17px">учеба</a></li>
</ul>
-<div id="bottom1">juick.com &copy; 2008-2018 &nbsp; <a href="/help/ru/contacts" rel="nofollow">Контакты</a> &middot; <a href="/help/" rel="nofollow">Помощь</a></div>
+<div id="bottom1">juick.com &copy; 2008-2019 &nbsp; <a href="/help/ru/contacts" rel="nofollow">Контакты</a> &middot; <a href="/help/" rel="nofollow">Помощь</a></div>
<div id="signup">
{{ i18n("messages","label.register") }}:
diff --git a/src/main/resources/templates/views/partial/footer.html b/src/main/resources/templates/views/partial/footer.html
index 35972254..bb6ccb97 100644
--- a/src/main/resources/templates/views/partial/footer.html
+++ b/src/main/resources/templates/views/partial/footer.html
@@ -8,7 +8,7 @@
<a href="https://vk.com/juick" rel="nofollow"><i data-icon="ei-sc-vk" data-size="m"></i></a>
<a href="https://www.facebook.com/JuickCom" rel="nofollow"><i data-icon="ei-sc-facebook" data-size="m"></i></a>
</div>
- <div id="footer-left">juick.com &copy; 2008-2018
+ <div id="footer-left">juick.com &copy; 2008-2019
{% if links | default ('') is not empty %}
<br/>{{ i18n("messages","label.sponsors") }}: {{ links | raw }}
{% endif %}
diff --git a/src/main/resources/templates/views/partial/message.html b/src/main/resources/templates/views/partial/message.html
index b1d27ae5..bb36b25e 100644
--- a/src/main/resources/templates/views/partial/message.html
+++ b/src/main/resources/templates/views/partial/message.html
@@ -8,9 +8,9 @@
</div>
<div class="msg-ts">
<a href="/{{ msg.user.name }}/{{ msg.mid }}">
- <time datetime="{{ msg.timestamp | timestamp | date('yyyy-MM-dd HH:mm:ss') }}Z"
- title="{{ msg.timestamp | timestamp | date('yyyy-MM-dd HH:mm:ss') }} GMT">
- {{ msg.timestamp | prettyTime }}
+ <time datetime="{{ msg.created | timestamp | date('yyyy-MM-dd HH:mm:ss') }}Z"
+ title="{{ msg.created | timestamp | date('yyyy-MM-dd HH:mm:ss') }} GMT">
+ {{ msg.created | prettyTime }}
</time>
</a>
</div>
diff --git a/src/main/resources/templates/views/pm_inbox.html b/src/main/resources/templates/views/pm_inbox.html
index 4f97bc86..f89b2923 100644
--- a/src/main/resources/templates/views/pm_inbox.html
+++ b/src/main/resources/templates/views/pm_inbox.html
@@ -12,7 +12,7 @@
<img src="{{ msg.user.avatar }}" alt="{{ msg.user.name }}"/>
</a>
</div>
- <div class="msg-ts">{{ msg.timestamp | prettyTime }}</div>
+ <div class="msg-ts">{{ msg.created | prettyTime }}</div>
</div>
<div class="msg-txt">{{ msg | formatMessage }}</div>
diff --git a/src/main/resources/templates/views/pm_sent.html b/src/main/resources/templates/views/pm_sent.html
index ace25301..f0af71d3 100644
--- a/src/main/resources/templates/views/pm_sent.html
+++ b/src/main/resources/templates/views/pm_sent.html
@@ -19,7 +19,7 @@
<img src="{{ msg.user.avatar }}" alt="{{ msg.user.name }}"/>
</a>
</div>
- <div class="msg-ts">{{ msg.timestamp | prettyTime }}</div>
+ <div class="msg-ts">{{ msg.created | prettyTime }}</div>
</div>
<div class="msg-txt">{{ msg | formatMessage }}</div>
</div>
diff --git a/src/main/resources/templates/views/thread.html b/src/main/resources/templates/views/thread.html
index 47dfd000..2092cc1b 100644
--- a/src/main/resources/templates/views/thread.html
+++ b/src/main/resources/templates/views/thread.html
@@ -13,9 +13,9 @@
</span>
<div class="msg-ts">
<a href="/{{ msg.user.name }}/{{ msg.mid }}">
- <time datetime="{{ msg.timestamp | timestamp | date('yyyy-MM-dd HH:mm:ss') }}Z"
- title="{{ msg.timestamp | timestamp | date('yyyy-MM-dd HH:mm:ss') }} GMT">
- {{ msg.timestamp | prettyTime }}
+ <time datetime="{{ msg.created | timestamp | date('yyyy-MM-dd HH:mm:ss') }}Z"
+ title="{{ msg.created | timestamp | date('yyyy-MM-dd HH:mm:ss') }} GMT">
+ {{ msg.created | prettyTime }}
</time>
</a>
</div>
@@ -99,7 +99,11 @@
{% if recomm is not empty %}
<div class="msg-recomms">{{ i18n("messages","message.recommendedBy") }}
{% for rec in recomm %}
- <a href="/{{ rec }}/">@{{ rec }}</a>{% if loop.index < (loop.length - 1) %}, {% endif %}
+ {% if rec.uri.toString() is empty %}
+ <a href="/{{ rec.name }}/">@{{ rec.name }}</a>{% if loop.index < (loop.length - 1) %}, {% endif %}
+ {% else %}
+ <a href="{{ rec.uri }}" data-user-uri="1">@{{ rec.name }}</a>{% if loop.index < (loop.length - 1) %}, {% endif %}
+ {% endif %}
{% endfor %}
{% if msg.likes > recomm.size() %}
&nbsp;{{ i18n("messages","message.recommendedOthers", msg.likes - recomm.size()) }}
@@ -136,9 +140,9 @@
{% endif %}
<div class="msg-ts">
<a href="/{{ msg.mid }}#{{ msg.rid }}">
- <time datetime="{{ msg.timestamp | timestamp | date('yyyy-MM-dd HH:mm:ss') }}Z"
- title="{{ msg.timestamp | timestamp | date('yyyy-MM-dd HH:mm:ss') }} GMT">
- {{ msg.timestamp | prettyTime }}
+ <time datetime="{{ msg.created | timestamp | date('yyyy-MM-dd HH:mm:ss') }}Z"
+ title="{{ msg.created | timestamp | date('yyyy-MM-dd HH:mm:ss') }} GMT">
+ {{ msg.created | prettyTime }}
</time>
</a>
</div>
diff --git a/src/test/java/com/juick/MessageTest.java b/src/test/java/com/juick/MessageTest.java
index 1d59a8db..eabeeb0f 100644
--- a/src/test/java/com/juick/MessageTest.java
+++ b/src/test/java/com/juick/MessageTest.java
@@ -20,6 +20,8 @@ package com.juick;
import com.juick.model.Entity;
import com.juick.test.util.MockUtils;
import com.juick.util.MessageUtils;
+import com.overzealous.remark.Options;
+import com.overzealous.remark.Remark;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
@@ -191,5 +193,39 @@ public class MessageTest {
assertThat(entities.stream().filter(e -> e.getType().equals("q")).count(), is(1L));
assertThat(entities.stream().filter(e -> e.getType().equals("u")).count(), is(1L));
assertThat(entities.stream().filter(e -> e.getType().equals("a")).count(), is(4L));
+ Entity yo = entities.stream().filter(e -> e.getType().equals("q")).findFirst().orElseThrow(IllegalStateException::new);
+ assertThat(yo.getText(), is("how ?"));
+ assertThat(yo.getStart(), is(0));
+ assertThat(yo.getEnd(), is(7));
+ }
+ @Test
+ public void ActivityStreamsHTMLtoMarkdownTest() {
+ String text = "<p><span class=\"h-card\"><a href=\"https://juick.com/stanislavv/\" class=\"u-url mention\">@<span>stanislavv</span></a></span> я в <span class=\"h-card\"><a href=\"https://mastodonsocial.ru/@rf\" class=\"u-url mention\">@<span>rf</span></a></span> выкладывал =)</p>";
+ Options options = new Options();
+ options.inlineLinks = true;
+ Remark remark = new Remark(options);
+ String parsed = remark.convertFragment(text);
+ }
+ @Test
+ public void messageFormatTest() {
+ String msg = "> quote\nmessage";
+ assertThat(MessageUtils.formatMessage(msg), is("<q>quote</q>message"));
+ String brokenComment = "<!-- read next";
+ assertThat(MessageUtils.formatMessage(brokenComment), is("&lt;!-- read next"));
+ String url = "[ya](http://ya.ru)";
+ assertThat(MessageUtils.formatMessage(url), is("<a href=\"http://ya.ru\" rel=\"nofollow\">ya</a>"));
+ String complexMessage = "У футболистов нет мозгов. Что в России, что в Беларуси:\n" +
+ "\n" +
+ ">Отец футболиста Лухвича, объехавшего пробку по тротуару: «Сына задержали, Infiniti арестовали» https://auto.onliner.by/2019/01/23/probka-9\n" +
+ "\n" +
+ "Вкратце: малолетний долбоёб ездил по встрече, по тротуарам, парковался где хотел и всё это выкладывал в сеть, мол, хули вы мне сделоете. Сделали. Ибо нехуй.";
+ String formattedMessage = "У футболистов нет мозгов. Что в России, что в Беларуси:<br/>\n<br/>\n" +
+ "<q>Отец футболиста Лухвича, объехавшего пробку по тротуару: «Сына задержали, Infiniti арестовали» <a href=\"https://auto.onliner.by/2019/01/23/probka-9\" rel=\"nofollow\">auto.onliner.by</a></q>" +
+ "<br/>\n" +
+ "Вкратце: малолетний долбоёб ездил по встрече, по тротуарам, парковался где хотел и всё это выкладывал в сеть, мол, хули вы мне сделоете. Сделали. Ибо нехуй.";
+
+ assertThat(MessageUtils.formatMessage(complexMessage), is(formattedMessage));
+ String multiQuote = "> quote line 1\n> quote line 2\nmessage";
+ assertThat(MessageUtils.formatMessage(multiQuote), is("<q>quote line 1<br/>\nquote line 2</q>message"));
}
}
diff --git a/src/test/java/com/juick/server/configuration/TestActivityConfiguration.java b/src/test/java/com/juick/server/configuration/TestActivityConfiguration.java
new file mode 100644
index 00000000..5daf4900
--- /dev/null
+++ b/src/test/java/com/juick/server/configuration/TestActivityConfiguration.java
@@ -0,0 +1,19 @@
+package com.juick.server.configuration;
+
+import com.juick.server.KeystoreManager;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.Resource;
+
+import java.io.IOException;
+
+@Configuration
+public class TestActivityConfiguration {
+ @Value("classpath:test.p12")
+ Resource keystoreFile;
+ @Bean
+ public KeystoreManager testKeystoreManager() throws IOException {
+ return new KeystoreManager(keystoreFile.getFile().getAbsolutePath(), "secret");
+ }
+}
diff --git a/src/test/java/com/juick/server/tests/ServerTests.java b/src/test/java/com/juick/server/tests/ServerTests.java
index deef6f30..7f46968f 100644
--- a/src/test/java/com/juick/server/tests/ServerTests.java
+++ b/src/test/java/com/juick/server/tests/ServerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2017, Juick
+ * Copyright (C) 2008-2019, Juick
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -19,6 +19,7 @@ package com.juick.server.tests;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gargoylesoftware.htmlunit.CookieManager;
import com.gargoylesoftware.htmlunit.WebClient;
@@ -33,27 +34,22 @@ import com.juick.model.PrivateChats;
import com.juick.model.TagStats;
import com.juick.server.*;
import com.juick.server.api.activity.model.Context;
-import com.juick.server.api.activity.model.activities.Create;
-import com.juick.server.api.activity.model.activities.Delete;
-import com.juick.server.api.activity.model.activities.Follow;
-import com.juick.server.api.activity.model.activities.Like;
-import com.juick.server.api.activity.model.activities.Undo;
+import com.juick.server.api.activity.model.activities.*;
import com.juick.server.api.activity.model.objects.Note;
import com.juick.server.api.activity.model.objects.Person;
import com.juick.server.api.webfinger.model.Account;
import com.juick.server.api.xnodeinfo2.model.NodeInfo;
import com.juick.server.util.HttpUtils;
import com.juick.server.util.ImageUtils;
-import com.juick.server.xmpp.helpers.XMPPStatus;
-import com.juick.server.xmpp.s2s.ConnectionIn;
+import com.juick.server.www.WebApp;
import com.juick.service.*;
import com.juick.service.component.MessageEvent;
+import com.juick.test.util.MockUtils;
import com.juick.util.DateFormattersHolder;
import com.juick.util.MessageUtils;
import com.mitchellbosecke.pebble.PebbleEngine;
import com.mitchellbosecke.pebble.error.PebbleException;
import com.mitchellbosecke.pebble.template.PebbleTemplate;
-import org.apache.commons.codec.CharEncoding;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.io.IOUtils;
@@ -70,16 +66,22 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
import org.springframework.http.*;
+import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.util.DigestUtils;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.ResourceAccessException;
+import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import org.w3c.dom.Document;
@@ -91,9 +93,6 @@ import rocks.xmpp.addr.Jid;
import rocks.xmpp.core.session.Extension;
import rocks.xmpp.core.session.XmppSession;
import rocks.xmpp.core.session.XmppSessionConfiguration;
-import rocks.xmpp.core.stanza.model.StanzaError;
-import rocks.xmpp.core.stanza.model.client.ClientMessage;
-import rocks.xmpp.core.stanza.model.errors.Condition;
import javax.inject.Inject;
import javax.servlet.http.Cookie;
@@ -105,7 +104,6 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
-import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
@@ -117,17 +115,20 @@ import java.sql.Timestamp;
import java.time.Instant;
import java.util.*;
import java.util.function.BiFunction;
-import java.util.function.Function;
-import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.StreamSupport;
+import static com.juick.server.api.activity.model.Context.ACTIVITY_MEDIA_TYPE;
import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
+import static org.springframework.test.web.client.ExpectedCount.times;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@@ -140,9 +141,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@TestPropertySource(properties = {
"broken_ssl_hosts=localhost,serverstorageisfull.tld",
"ios_app_id=12345678.com.juick.ExampleApp",
- "xmppbot_jid=juick@localhost/Juick",
- "hostname=localhost",
- "componentname=localhost",
"spring.jackson.default-property-inclusion=non_default"
})
@AutoConfigureMockMvc
@@ -163,12 +161,8 @@ public class ServerTests {
@Inject
private ObjectMapper jsonMapper;
@Inject
- private XMPPServer server;
- @Inject
private CommandsManager commandsManager;
@Inject
- private XMPPConnection router;
- @Inject
private SubscriptionService subscriptionService;
@Inject
private PrivacyQueriesService privacyQueriesService;
@@ -188,10 +182,6 @@ public class ServerTests {
private ServerManager serverManager;
@Inject
private KeystoreManager keystoreManager;
- @Value("${hostname:localhost}")
- private Jid jid;
- @Value("${xmppbot_jid:juick@localhost}")
- private Jid botJid;
@Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
private String tmpDir;
@Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
@@ -204,6 +194,32 @@ public class ServerTests {
private SignatureManager signatureManager;
@Inject
private ActivityPubManager activityPubManager;
+ @Inject
+ private WebApp webApp;
+ @Inject
+ private RestTemplate apClient;
+
+ @Value("classpath:mocks/activity/testuser.json")
+ private Resource testuserResponse;
+ @Value("classpath:mocks/activity/testfollow.json")
+ private Resource testfollowRequest;
+ @Value("classpath:static/av-96.png")
+ private Resource defaultAvatar;
+ @Value("classpath:cmyk.jpg")
+ private Resource cmykJpeg;
+ @Value("classpath:nojfif.jpg")
+ private Resource nojfif;
+ @Value("classpath:hubzilla_activity.json")
+ private Resource hubzillaActivity;
+ @Value("classpath:hubzilla_follow.json")
+ private Resource hubzillaFollow;
+ @Value("classpath:announce.json")
+ private Resource noteWithDocument;
+ @Value("classpath:2936611-57.jpg")
+ private Resource jpegNoJfifTiff;
+
+ @Inject
+ private KeystoreManager testKeystoreManager;
private static User ugnich, freefd, juick;
static String ugnichName, ugnichPassword, freefdName, freefdPassword, juickName, juickPassword;
@@ -217,10 +233,16 @@ public class ServerTests {
FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-1024"));
FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-512"));
FileSystemUtils.deleteRecursively(Paths.get(imgDir, "ps"));
+ FileSystemUtils.deleteRecursively(Paths.get(imgDir, "a"));
+ FileSystemUtils.deleteRecursively(Paths.get(imgDir, "ao"));
+ FileSystemUtils.deleteRecursively(Paths.get(imgDir, "as"));
Files.createDirectory(Paths.get(imgDir, "p"));
Files.createDirectory(Paths.get(imgDir, "photos-1024"));
Files.createDirectory(Paths.get(imgDir, "photos-512"));
Files.createDirectory(Paths.get(imgDir, "ps"));
+ Files.createDirectory(Paths.get(imgDir, "a"));
+ Files.createDirectory(Paths.get(imgDir, "ao"));
+ Files.createDirectory(Paths.get(imgDir, "as"));
if (!isSetUp) {
ugnichName = "ugnich";
ugnichPassword = "secret";
@@ -339,7 +361,7 @@ public class ServerTests {
Message msg3 = messagesService.getMessage(mid2).get();
assertEquals(2, msg3.getReplies());
- assertEquals("weather", msg3.getTags().get(0).getName());
+ assertEquals("weather", msg3.getTags().stream().findFirst().get().getName());
assertEquals(ugnich.getUid(), userService.checkPassword(ugnich.getName(), "x"));
assertEquals(-1, userService.checkPassword(ugnich.getName(), "xy"));
@@ -411,7 +433,7 @@ public class ServerTests {
Timestamp.class, mid).toInstant();
assertThat(rts, greaterThan(ts));
Message msg = messagesService.getReply(mid, rid);
- assertThat(rts, equalTo(msg.getTimestamp()));
+ assertThat(rts, equalTo(msg.getCreated()));
messagesService.deleteMessage(ugnich_id, mid);
}
@@ -436,11 +458,10 @@ public class ServerTests {
@Test
public void homeTestWithMessages() throws Exception {
String msgText = "Привет, я - Угнич";
- CommandResult result = commandsManager.processCommand(ugnich, msgText, URI.create("http://static.juick.com/settings/facebook.png"));
+ CommandResult result = commandsManager.processCommand(ugnich, msgText, URI.create("https://static.juick.com/settings/facebook.png"));
int mid = result.getNewMessage().get().getMid();
Message msg = messagesService.getMessage(mid).get();
tagService.createTag("тест");
- ClassPathResource defaultAvatar = new ClassPathResource("static/av-96.png");
String hash = DigestUtils.md5DigestAsHex(IOUtils.toByteArray(defaultAvatar.getInputStream()));
mockMvc.perform(
get("/api/home")
@@ -449,7 +470,7 @@ public class ServerTests {
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$[0].mid", is(msg.getMid())))
.andExpect(jsonPath("$[0].timestamp",
- is(DateFormattersHolder.getMessageFormatterInstance().format(msg.getTimestamp()))))
+ is(DateFormattersHolder.getMessageFormatterInstance().format(msg.getCreated()))))
.andExpect(jsonPath("$[0].body", is(msg.getText())))
.andExpect(jsonPath("$[0].attachment.url",
is(String.format("https://i.juick.com/p/%d.png", msg.getMid()))))
@@ -481,6 +502,11 @@ public class ServerTests {
.header("Origin", "http://api.example.net"))
.andExpect(status().isOk())
.andExpect(header().string("Access-Control-Allow-Origin", "*"));
+ mockMvc.perform(
+ get("/u/ugnich")
+ .header("Origin", "http://api.example.net"))
+ .andExpect(status().isOk())
+ .andExpect(header().string("Access-Control-Allow-Origin", "*"));
}
@Test
@@ -675,63 +701,6 @@ public class ServerTests {
.andExpect(xpath("/rss/channel/description").string("The latest messages at Juick"));
}
@Test
- public void statusPageIsUp() throws Exception {
- mockMvc.perform(get("/api/status").with(httpBasic(ugnichName, ugnichPassword))).andExpect(status().isOk());
- assertThat(server.getJid(), equalTo(jid));
- }
- @Test
- public void botIsUpAndProcessingResourceConstraints() throws Exception {
- jdbcTemplate.execute("DELETE FROM users WHERE nick='renha'");
- int renhaId = userService.createUser("renha", "umnnbt");
- Jid from = Jid.of("renha@serverstorageisfull.tld");
- jdbcTemplate.update("INSERT INTO jids(user_id,jid,active) VALUES(?,?,?)",
- renhaId, from.toEscapedString(), 1);
- rocks.xmpp.core.stanza.model.Message xmppMessage = new rocks.xmpp.core.stanza.model.Message();
- xmppMessage.setType(rocks.xmpp.core.stanza.model.Message.Type.ERROR);
- xmppMessage.setFrom(from);
- xmppMessage.setTo(botJid);
- StanzaError err = new StanzaError(StanzaError.Type.CANCEL, Condition.RESOURCE_CONSTRAINT);
- xmppMessage.setError(err);
- Function<Integer, Boolean> isActive = f -> jdbcTemplate.queryForObject("SELECT active FROM jids WHERE user_id=?", Integer.class, f) == 1;
- assertThat(isActive.apply(renhaId), equalTo(true));
- ClientMessage result = router.incomingMessage(xmppMessage);
- assertNull(result);
- assertThat(isActive.apply(renhaId), equalTo(false));
- xmppMessage.setError(null);
- xmppMessage.setType(rocks.xmpp.core.stanza.model.Message.Type.CHAT);
- xmppMessage.setBody("On");
- result = router.incomingMessage(xmppMessage);
- assertThat(result.getBody(), equalTo("XMPP notifications are activated"));
- assertTrue(isActive.apply(renhaId));
- xmppMessage.setBody("*test test");
- result = router.incomingMessage(xmppMessage);
- assertThat(result.getBody(), startsWith("New message posted"));
- xmppMessage.setFrom(from);
- xmppMessage.setBody("PING");
- result = router.incomingMessage(xmppMessage);
- assertThat(result.getBody(), equalTo("PONG"));
- int secretlySadId = userService.createUser("secretlysad", "bbk");
- xmppMessage.setTo(botJid.withLocal("secretlysad"));
- xmppMessage.setBody("What's up?");
- result = router.incomingMessage(xmppMessage);
- assertThat(result, is(nullValue()));
- xmppMessage.setTo(botJid);
- xmppMessage.setBody("@secretlysad Hey!");
- result = router.incomingMessage(xmppMessage);
- assertThat(result.getBody(), is("Private message sent"));
- assertThat(pmQueriesService.getPMMessages(renhaId, secretlySadId).size(), is(2));
- String xml = "<message xmlns=\"jabber:server\" from=\"" + botJid + "\" to=\"renha@serverstorageisfull.tld\" type=\"chat\"><body>@yo:\n" +
- "343432434\n" +
- "\n" +
- "#2 http://juick.com/2</body><thread>juick-2</thread><juick xmlns=\"http://juick.com/message\" mid=\"2\" privacy=\"1\" quote=\"\" replyto=\"0\" rid=\"0\" ts=\"2018-04-10 06:58:23\"><body>343432434</body><updated></updated><user xmlns=\"http://juick.com/user\" uname=\"yo\" uid=\"2\"></user></juick><nick xmlns=\"http://jabber.org/protocol/nick\">@yo</nick></message>";
- result = router.incomingMessage((rocks.xmpp.core.stanza.model.Message)server.parse(xml));
- String active = "<message xmlns=\"jabber:server\" from=\"renha@serverstorageisfull.tld/work\" to=\""
- + botJid.asBareJid().toEscapedString() + "\" type=\"chat\" id=\"purple553384c6\"><active xmlns=\"http://jabber.org/protocol/chatstates\"></active></message>";
- result = router.incomingMessage((rocks.xmpp.core.stanza.model.Message)server.parse(active));
- xmppMessage.setFrom(botJid);
- // TODO: assert events
- }
- @Test
public void botCommandsTests() throws Exception {
assertThat(commandsManager.processCommand(AnonymousUser.INSTANCE, "PING", emptyUri).getText(), is("PONG"));
// subscription commands have two lines, others have 1
@@ -743,21 +712,21 @@ public class ServerTests {
int uid = userService.createUser("me", "secret");
User user = userService.getUserByUID(uid).orElse(AnonymousUser.INSTANCE);
Tag yo = tagService.getTag("yo", true);
- Message msg = commandsManager.processCommand(user, "*yo yoyo", URI.create("http://static.juick.com/settings/facebook.png")).getNewMessage().get();
+ Message msg = commandsManager.processCommand(user, "*yo yoyo", URI.create("https://static.juick.com/settings/facebook.png")).getNewMessage().get();
assertThat(msg.getAttachmentType(), is("png"));
- Message msgreply = commandsManager.processCommand(user, "#" + msg.getMid() + " yyy", HttpUtils.downloadImage(URI.create("http://static.juick.com/settings/xmpp.png").toURL(), tmpDir)).getNewMessage().get();
+ Message msgreply = commandsManager.processCommand(user, "#" + msg.getMid() + " yyy", HttpUtils.downloadImage(URI.create("https://static.juick.com/settings/xmpp.png").toURL(), tmpDir)).getNewMessage().get();
assertThat(msgreply.getAttachmentType(), equalTo("png"));
assertEquals("text should match", "yoyo",
messagesService.getMessage(msg.getMid()).get().getText());
assertEquals("tag should match", "yo",
tagService.getMessageTags(msg.getMid()).get(0).getTag().getName());
- CommandResult yoyoMsg = commandsManager.processCommand(user, "*yo", URI.create("http://static.juick.com/settings/facebook.png"));
+ CommandResult yoyoMsg = commandsManager.processCommand(user, "*yo", URI.create("https://static.juick.com/settings/facebook.png"));
assertTrue(yoyoMsg.getNewMessage().isPresent());
- assertThat(yoyoMsg.getNewMessage().get().getTags().get(0), is(yo));
+ assertThat(yoyoMsg.getNewMessage().get().getTags().stream().findFirst().get(), is(yo));
Message msg2 = yoyoMsg.getNewMessage().get();
int mid = msg2.getMid();
Timestamp last = jdbcTemplate.queryForObject("SELECT lastmessage FROM users WHERE id=?", Timestamp.class, user.getUid());
- assertThat(last.toInstant(), equalTo(yoyoMsg.getNewMessage().get().getTimestamp()));
+ assertThat(last.toInstant(), equalTo(yoyoMsg.getNewMessage().get().getCreated()));
assertEquals("should be message", true,
commandsManager.processCommand(user, String.format("#%d", mid), emptyUri).getText().startsWith("@me"));
int readerUid = userService.createUser("dummyReader", "dummySecret");
@@ -795,14 +764,14 @@ public class ServerTests {
String expectedThirdReply = "Reply posted.\n#" + mid + "/3 "
+ "https://juick.com/m/" + mid + "#3";
assertEquals("should be second reply", expectedSecondReply,
- commandsManager.processCommand(user, "#" + mid + " yoyo", URI.create("http://static.juick.com/settings/facebook.png")).getText());
+ commandsManager.processCommand(user, "#" + mid + " yoyo", URI.create("https://static.juick.com/settings/facebook.png")).getText());
assertEquals("should be third reply", expectedThirdReply,
commandsManager.processCommand(user, " \t\n #" + mid + "/2 ",
- URI.create("http://static.juick.com/settings/facebook.png")).getText());
+ URI.create("https://static.juick.com/settings/facebook.png")).getText());
Message reply = messagesService.getReplies(user, mid).stream().filter(m -> m.getRid() == 3).findFirst()
.orElse(new Message());
Timestamp lastreply = jdbcTemplate.queryForObject("SELECT lastmessage FROM users WHERE id=?", Timestamp.class, user.getUid());
- assertThat(lastreply.toInstant(), equalTo(reply.getTimestamp()));
+ assertThat(lastreply.toInstant(), equalTo(reply.getCreated()));
assertEquals("should be reply to second comment", 2, reply.getReplyto());
assertThat(commandsManager.processCommand(readerUser, "#" + mid + " *yo *there", emptyUri)
.getText(), startsWith("Reply posted"));
@@ -857,11 +826,11 @@ public class ServerTests {
"> }";
String codeAndTags = "*code\n" + expectedCodeMessage;
Message codeAndTagsMessage = commandsManager.processCommand(user, codeAndTags, emptyUri).getNewMessage().get();
- List<Tag> codeAndTagsTags = codeAndTagsMessage.getTags();
+ Set<Tag> codeAndTagsTags = codeAndTagsMessage.getTags();
assertEquals("expected single tag", 1,
codeAndTagsTags.size());
assertEquals("the single tag should be the 'code'", "code",
- codeAndTagsTags.get(0).getName());
+ codeAndTagsTags.stream().findFirst().get().getName());
assertEquals("and the message should be with a C-code and without tags", expectedCodeMessage,
codeAndTagsMessage.getText());
CommandResult result = commandsManager.processCommand(user, "*one *two *three *four *five *six test", emptyUri);
@@ -885,7 +854,7 @@ public class ServerTests {
data = "* \u043c\u0443\u0441\u043e\u0440\\n\u0423 \u043c\u0435\u043d\u044f \u043a\u0430\u0436\u0434\u0443\u044e \u043d\u0435\u0434\u0435\u043b\u044e \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043f\u043e 4-5 \u0431\u0443\u0442\u044b\u043b\u043e\u043a 1,5\u043b \u041f\u0415\u0422. \u041c\u043d\u0435 \u0433\u0435\u043c\u043e\u0440\u043d\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u043e \u043a\u0438\u043b\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0438\u043b\u0438 \u043f\u043e 5\u043a\u0433 \u044d\u0442\u043e\u0433\u043e \u043c\u0443\u0441\u043e\u0440\u0430, \u0447\u0442\u043e\u0431\u044b \u0432\u0435\u0437\u0442\u0438 \u0435\u0433\u043e \u0435\u0449\u0435 \u043a\u0443\u0434\u0430-\u0442\u043e.\\n\u041d\u0435, \u043d\u0443 \u0435\u0441\u0442\u044c \u043b\u044e\u0434\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0442 \u0432\u0442\u043e\u0440\u0441\u044b\u0440\u044c\u0435 \u043f\u043e \u043c\u0443\u0441\u043e\u0440\u043a\u0430\u043c, \u0441\u0432\u0430\u043b\u043a\u0430\u043c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0434\u0435\u043d\u044c\u0433\u0438 \u043d\u0443\u0436\u043d\u044b. \u0418 \u0431\u044b\u0432\u0430\u044e\u0442 \u0441\u0442\u043e\u044f\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b-\u043a\u043b\u0435\u0442\u043a\u0438 \u0434\u043b\u044f \u043f\u043b\u0430\u0441\u0442\u0438\u043a\u0430, \u043d\u043e \u0442\u0430\u043a \u043a\u0430\u043a \u043c\u0443\u0441\u043e\u0440 \u0432\u044b\u0432\u043e\u0437\u044f\u0442 \u043d\u0435 \u0447\u0430\u0441\u0442\u043e \u0438\u043b\u0438 \u043b\u044e\u0434\u0438 \u0432\u043d\u0435\u0437\u0430\u043f\u043d\u043e \u0432\u044b\u043a\u0438\u0434\u044b\u0432\u0430\u044e\u0442 \u043c\u043d\u043e\u0433\u043e \u043c\u0443\u0441\u043e\u0440\u0430, \u0442\u043e \u0432 \u0442\u043e\u0439 \u043a\u043b\u0435\u0442\u043a\u0435 \u0442\u043e\u0442 \u043c\u0443\u0441\u043e\u0440, \u0447\u0442\u043e \u043d\u0435 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u043b\u0441\u044f \u0432 \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445.";
result = commandsManager.processCommand(user, String.format("%s %s", tags, data), emptyUri);
assertThat(result.getNewMessage().get().getTags().size(), equalTo(2));
- assertThat(result.getNewMessage().get().getTags().get(0).getName(), equalTo("Киев"));
+ assertThat(result.getNewMessage().get().getTags().stream().findFirst().get().getName(), equalTo("Киев"));
assertThat(result.getNewMessage().get().getText(), equalTo(data));
result = commandsManager.processCommand(user, "S @unknown-user", emptyUri);
assertThat(result.getNewMessage(), is(Optional.empty()));
@@ -933,7 +902,7 @@ public class ServerTests {
mockMvc.perform(get("/api/thread?mid=" + mid + "&hash=" + freefdHash))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].recommendations.length()", is(1)))
- .andExpect(jsonPath("$[0].recommendations[0]", is(freefdName)));
+ .andExpect(jsonPath("$[0].recommendations[0].uname", is(freefdName)));
mockMvc.perform(post("/api/like?mid=" + freefdMid + "&hash=" + freefdHash))
.andExpect(status().isForbidden());
}
@@ -1029,8 +998,8 @@ public class ServerTests {
tagService.updateTags(newMid, Collections.singletonList(banned));
assertThat(messagesService.getMessage(newMid).get().getTags().size(), is(0));
privacyQueriesService.blacklistUser(freefd, userService.getUserByUID(newUid).orElse(AnonymousUser.INSTANCE));
- assertTrue(messagesService.getMessages(AnonymousUser.INSTANCE, messagesService.getMyFeed(freefd.getUid(), 0, true))
- .stream().noneMatch(m -> m.getMid() == newMid));
+ assertTrue(messagesService.getMyFeed(freefd.getUid(), 0, true)
+ .stream().noneMatch(m -> m == newMid));
}
@Test
public void tagsShouldBeDeserializedFromXml() throws JAXBException {
@@ -1055,18 +1024,21 @@ public class ServerTests {
Tag xmlTag = (Tag) unmarshaller.unmarshal(new StringReader(tag));
assertThat(xmlTag.getName(), equalTo("yo"));
Message juickMessage = xmppMessage.getExtension(Message.class);
- assertThat(juickMessage.getTags().get(0).getName(), equalTo("yo"));
+ List<Tag> tags = new ArrayList<>(juickMessage.getTags());
+ assertThat(tags.get(0).getName(), equalTo("yo"));
}
@Test
public void messageParserSerializer() throws ParserConfigurationException,
IOException, SAXException, JAXBException {
+ Set<Tag> tags = MessageUtils.parseTags("test test" + (char) 0xA0 + "2 test3");
+ List<Tag> tagList = new ArrayList<>(tags);
+ assertEquals("First tag must be", "test", tagList.get(0).getName());
+ assertEquals("Third tag must be", "test3", tagList.get(2).getName());
+ assertEquals("Count of tags must be", 3, tagList.size());
Message msg = new Message();
- msg.setTags(MessageUtils.parseTags("test test" + (char) 0xA0 + "2 test3"));
- assertEquals("First tag must be", "test", msg.getTags().get(0).getName());
- assertEquals("Third tag must be", "test3", msg.getTags().get(2).getName());
- assertEquals("Count of tags must be", 3, msg.getTags().size());
+ msg.setTags(tags);
Instant currentDate = Instant.now();
- msg.setTimestamp(currentDate);
+ msg.setCreated(currentDate);
String jsonMessage = jsonMapper.writeValueAsString(msg);
assertEquals("date should be in timestamp field", DateFormattersHolder.getMessageFormatterInstance().format(currentDate),
JsonPath.read(jsonMessage, "$.timestamp"));
@@ -1081,7 +1053,7 @@ public class ServerTests {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
- Document doc = db.parse(new ByteArrayInputStream(sw.toString().getBytes(CharEncoding.UTF_8)));
+ Document doc = db.parse(new ByteArrayInputStream(sw.toString().getBytes(StandardCharsets.UTF_8)));
Node juickNode = doc.getDocumentElement();
NamedNodeMap attrs = juickNode.getAttributes();
assertEquals("date should be in ts field", DateFormattersHolder.getMessageFormatterInstance().format(currentDate),
@@ -1168,7 +1140,7 @@ public class ServerTests {
}
@Test
public void cmykJpegShouldBeProcessedCorrectly() throws Exception {
- CommandResult postJpgCmyk = commandsManager.processCommand(ugnich, "YO", new ClassPathResource("cmyk.jpg").getURI());
+ CommandResult postJpgCmyk = commandsManager.processCommand(ugnich, "YO", cmykJpeg.getURI());
assertThat(postJpgCmyk.getNewMessage().isPresent(), is(true));
int mid = postJpgCmyk.getNewMessage().get().getMid();
File originalFile = Paths.get(imgDir, "p", String.format("%d.jpg", mid)).toFile();
@@ -1182,7 +1154,7 @@ public class ServerTests {
}
@Test
public void JpegWithoutJfifShouldBeProcessedCorrectly() throws Exception {
- CommandResult postJpgCmyk = commandsManager.processCommand(ugnich, "YO", new ClassPathResource("nojfif.jpg").getURI());
+ CommandResult postJpgCmyk = commandsManager.processCommand(ugnich, "YO", nojfif.getURI());
assertThat(postJpgCmyk.getNewMessage().isPresent(), is(true));
int mid = postJpgCmyk.getNewMessage().get().getMid();
File originalFile = Paths.get(imgDir, "p", String.format("%d.jpg", mid)).toFile();
@@ -1210,12 +1182,19 @@ public class ServerTests {
assertThat(postJpgiPhone.getNewMessage().get().getAttachment().getHeight(), is(1280));
assertThat(postJpgiPhone.getNewMessage().get().getAttachment().getMedium().getHeight(), is(1024));
assertThat(postJpgiPhone.getNewMessage().get().getAttachment().getSmall().getHeight(), is(512));
+ CommandResult postNojfifTiff = commandsManager.processCommand(ugnich, "YO2", jpegNoJfifTiff.getURI());
+ assertThat(postNojfifTiff.getNewMessage().isPresent(), is(true));
+ int mid2 = postNojfifTiff.getNewMessage().get().getMid();
+ File originalFile2 = Paths.get(imgDir, "p", String.format("%d.jpg", mid2)).toFile();
+ assertThat(originalFile2.exists(), is(true));
+ File mediumFile2 = Paths.get(imgDir, "photos-1024", String.format("%d.jpg", mid2)).toFile();
+ assertThat(mediumFile2.exists(), is(true));
}
@Test
public void changeExtensionWhenReceiveFileWithWrongContentType() throws Exception {
Path pngOutput = Paths.get(tmpDir, "cmyk.png");
Files.deleteIfExists(pngOutput);
- Files.copy(Paths.get(new ClassPathResource("cmyk.jpg").getURI()), pngOutput);
+ Files.copy(Paths.get(cmykJpeg.getURI()), pngOutput);
assertThat(pngOutput.toFile().exists(), is(true));
CommandResult postJpgCmyk = commandsManager.processCommand(ugnich, "YO", pngOutput.toUri());
assertThat(postJpgCmyk.getNewMessage().isPresent(), is(true));
@@ -1231,7 +1210,7 @@ public class ServerTests {
Message original = jsonMapper.readValue(result.getResponse().getContentAsString(), CommandResult.class)
.getNewMessage().get();
assertThat(original.getText(), equalTo("YO"));
- assertThat(original.getUpdatedAt(), equalTo(original.getTimestamp()));
+ assertThat(original.getUpdatedAt(), equalTo(original.getCreated()));
// to have updated_at greater than ts
Thread.sleep(1000);
result = mockMvc.perform(post("/api/update").with(httpBasic(ugnichName, ugnichPassword))
@@ -1240,7 +1219,7 @@ public class ServerTests {
Message edited = jsonMapper.readValue(result.getResponse().getContentAsString(), CommandResult.class)
.getNewMessage().get();
assertThat(edited.getText(), equalTo("PEOPLE"));
- assertThat(edited.getUpdatedAt(), greaterThan(edited.getTimestamp()));
+ assertThat(edited.getUpdatedAt(), greaterThan(edited.getCreated()));
mockMvc.perform(post("/api/update").with(httpBasic(freefdName, freefdPassword))
.param("mid", String.valueOf(original.getMid()))
.param("body", "PEOPLE")).andExpect(status().is(403));
@@ -1249,7 +1228,7 @@ public class ServerTests {
.param("body", "HEY")).andExpect(status().is2xxSuccessful()).andReturn();
CommandResult comment = jsonMapper.readValue(result.getResponse().getContentAsString(), CommandResult.class);
assertThat(comment.getNewMessage().get().getText(), is("HEY"));
- assertThat(comment.getNewMessage().get().getUpdatedAt(), is(comment.getNewMessage().get().getTimestamp()));
+ assertThat(comment.getNewMessage().get().getUpdatedAt(), is(comment.getNewMessage().get().getCreated()));
// to have updated_at greater than ts
Thread.sleep(1000);
result = mockMvc.perform(post("/api/update").with(httpBasic(freefdName, freefdPassword))
@@ -1259,7 +1238,7 @@ public class ServerTests {
Message editedComment = jsonMapper.readValue(result.getResponse().getContentAsString(), CommandResult.class)
.getNewMessage().get();
assertThat(editedComment.getText(), is("HEY, JOE"));
- assertThat(editedComment.getUpdatedAt(), greaterThan(editedComment.getTimestamp()));
+ assertThat(editedComment.getUpdatedAt(), greaterThan(editedComment.getCreated()));
messagesService.deleteMessage(ugnich.getUid(), original.getMid());
}
@Test
@@ -1316,25 +1295,6 @@ public class ServerTests {
assertThat(subscriptionService.getUsersSubscribedToComments(msg, reply).size(), is(0));
}
@Test
- public void xmppStatusApi() throws Exception {
- Supplier<XMPPStatus> getStatus = () -> {
- try {
- MvcResult result = mockMvc.perform(get("/api/xmpp-status").with(httpBasic(ugnichName, ugnichPassword)))
- .andExpect(status().isOk()).andReturn();
- return jsonMapper.readValue(result.getResponse().getContentAsString(), XMPPStatus.class);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- };
- assertThat(getStatus.get().getInbound(), is(nullValue()));
- ConnectionIn test = new ConnectionIn(server, new Socket("localhost", server.getServerPort()));
- test.from.add(Jid.of("test"));
- server.getInConnections().clear();
- server.addConnectionIn(test);
- assertThat(getStatus.get().getInbound().size(), is(1));
- }
- @Test
public void credentialsShouldNeverBeSerialized() throws Exception {
int uid = userService.createUser("yyy", "xxxx");
User yyy = userService.getUserByUID(uid).get();
@@ -1405,11 +1365,18 @@ public class ServerTests {
assertThat(messagesService.recommendMessage(mid, ermineId), is(MessagesService.RecommendStatus.Added));
assertThat(messagesService.recommendMessage(mid, fmapId), is(MessagesService.RecommendStatus.Added));
assertThat(messagesService.recommendMessage(mid, pogoId), is(MessagesService.RecommendStatus.Added));
- assertThat(messagesService.getMessage(mid).get().getLikes(), is(3));
- assertThat(CollectionUtils.isEqualCollection(messagesService.getMessageRecommendations(mid), Arrays.asList("fmap", "ermine", "pogo")), is(true));
- privacyQueriesService.blacklistUser(userService.getUserByName("monstreek"), userService.getUserByName("pogo"));
- assertThat(messagesService.getMessage(mid).get().getLikes(), is(3));
- assertThat(CollectionUtils.isEqualCollection(messagesService.getMessageRecommendations(mid), Arrays.asList("fmap", "ermine")), is(true));
+ jdbcTemplate.update("INSERT INTO favorites(user_id, user_uri, message_id, like_id, ts) " +
+ "values (0, 'http://example.com/u/test', ?, 1, now())", mid);
+ assertThat(messagesService.getMessage(mid).get().getLikes(), is(4));
+ assertThat(CollectionUtils.isEqualCollection(messagesService.getMessageRecommendations(mid)
+ .stream().map(User::getName).collect(Collectors.toList()),
+ Arrays.asList("fmap", "ermine", "pogo", "Anonymous")), is(true));
+ privacyQueriesService.blacklistUser(userService.getUserByName("monstreek"),
+ userService.getUserByName("pogo"));
+ assertThat(messagesService.getMessage(mid).get().getLikes(), is(4));
+ assertThat(CollectionUtils.isEqualCollection(messagesService.getMessageRecommendations(mid)
+ .stream().map(User::getName).collect(Collectors.toList()),
+ Arrays.asList("fmap", "ermine", "Anonymous")), is(true));
}
@Test
public void bannedUserShouldNotBeVisibleToOthers() {
@@ -1696,9 +1663,10 @@ public class ServerTests {
CommandResult result = commandsManager.processCommand(ugnich, "*test1 *test2 *test1 test3", emptyUri);
assertThat(result.getNewMessage().isPresent(), is(true));
Message msg = result.getNewMessage().get();
- assertThat(msg.getTags().size(), is (2));
- assertThat(msg.getTags().get(0).getName(), is("test1"));
- assertThat(msg.getTags().get(1).getName(), is("test2"));
+ List<Tag> tags = new ArrayList<>(msg.getTags());
+ assertThat(tags.size(), is (2));
+ assertThat(tags.get(0).getName(), is("test1"));
+ assertThat(tags.get(1).getName(), is("test2"));
assertThat(msg.getText(), is("test3"));
}
@Test
@@ -1759,6 +1727,7 @@ public class ServerTests {
replyNote.setTo(Collections.singletonList(activityPubManager.personUri(ugnich)));
replyNote.setContent("HI");
Create create = new Create();
+ create.setId(replyNote.getId());
create.setActor("http://localhost:8080/u/freefd");
create.setObject(replyNote);
signatureManager.post((Person) signatureManager.getContext(URI.create("http://localhost:8080/u/freefd")).get(),
@@ -1776,6 +1745,55 @@ public class ServerTests {
signatureManager.post(from, to, follow);
}
@Test
+ public void serviceSignatureAuth() throws Exception {
+ String meUri = "/api/me";
+ String testHost = "localhost:8080";
+ Person ugnichPerson = (Person) signatureManager.discoverPerson("ugnich@localhost:8080").get();
+ Instant now = Instant.now();
+ String requestDate = DateFormattersHolder.getHttpDateFormatter().format(now);
+ String signatureString = signatureManager.addSignature(ugnichPerson, testHost, "GET", meUri, requestDate);
+ MvcResult me = mockMvc.perform(get("/api/me")
+ .header("Host", testHost)
+ .header("Date", requestDate)
+ .header("Signature", signatureString))
+ .andExpect(status().isOk())
+ .andReturn();
+ User meUser = jsonMapper.readValue(me.getResponse().getContentAsString(), User.class);
+ assertThat(meUser, is(ugnich));
+ String testuserResponseString = IOUtils.toString(testuserResponse.getInputStream(), StandardCharsets.UTF_8);
+ ClientHttpRequestFactory originalRequestFactory = apClient.getRequestFactory();
+ URI testuserUri = URI.create("https://example.com/u/testuser");
+ URI testuserkeyUri = URI.create("https://example.com/u/testuser#main-key");
+ MockRestServiceServer restServiceServer = MockRestServiceServer.createServer(apClient);
+ restServiceServer.expect(times(3), requestTo(testuserUri))
+ .andRespond(withSuccess(testuserResponseString, MediaType.APPLICATION_JSON_UTF8));
+ restServiceServer.expect(times(3), requestTo(testuserkeyUri))
+ .andRespond(withSuccess(testuserResponseString, MediaType.APPLICATION_JSON_UTF8));
+ Person testuser = (Person)signatureManager.getContext(testuserUri).get();
+ Assert.assertThat(testuser.getPublicKey().getPublicKeyPem(), is(testKeystoreManager.getPublicKeyPem()));
+ Instant now2 = Instant.now();
+ String testRequestDate = DateFormattersHolder.getHttpDateFormatter().format(now2);
+ String inboxUri = "/api/inbox";
+ String testSignatureString =
+ signatureManager.addSignature(testuser, testHost, "POST",
+ inboxUri, testRequestDate, testKeystoreManager);
+ mockMvc.perform(post(inboxUri)
+ .header("Host", testHost)
+ .header("Date", testRequestDate)
+ .header("Signature", testSignatureString)
+ .contentType(Context.LD_JSON_MEDIA_TYPE)
+ .content(IOUtils.toByteArray(testfollowRequest.getInputStream())))
+ .andExpect(status().isAccepted());
+ mockMvc.perform(post(inboxUri)
+ .header("Host", "wronghost")
+ .header("Date", testRequestDate)
+ .header("Signature", testSignatureString)
+ .contentType(Context.LD_JSON_MEDIA_TYPE)
+ .content(IOUtils.toByteArray(testfollowRequest.getInputStream())))
+ .andExpect(status().isUnauthorized());
+ apClient.setRequestFactory(originalRequestFactory);
+ }
+ @Test
public void hostmeta() throws Exception {
MvcResult result = mockMvc.perform(get("/.well-known/host-meta"))
.andExpect(status().isOk()).andReturn();
@@ -1858,4 +1876,139 @@ public class ServerTests {
jdbcTemplate.update("INSERT INTO facebook(user_id, fb_id) VALUES(?, ?)", ugnich.getUid(), "100001866137681");
assertThat(userService.getUserByName("ugnich").isVerified(), is(true));
}
+ @Test
+ public void avatarUploadOverApi() throws Exception {
+ ClassPathResource defaultAvatar = new ClassPathResource("static/av-96.png");
+ String hash = DigestUtils.md5DigestAsHex(IOUtils.toByteArray(defaultAvatar.getInputStream()));
+ assertThat(webApp.getAvatarUrl(userService.getUserByName(freefdName)), is(String.format("http://localhost:8080/av-96-%s.png", hash)));
+
+ ClassPathResource newAvatar = new ClassPathResource("static/durov.png");
+ byte[] newAvatarData = IOUtils.toByteArray(newAvatar.getInputStream());
+ mockMvc.perform(MockMvcRequestBuilders.multipart("/api/me/upload")
+ .file("avatar", newAvatarData)
+ .with(httpBasic(freefdName, freefdPassword))
+ ).andExpect(status().isOk());
+ String newHash = DigestUtils.md5DigestAsHex(newAvatarData);
+ URI newUri = Paths.get(imgDir, "ao", String.format("%d.png", freefd.getUid())).toUri();
+ assertThat(DigestUtils.md5DigestAsHex(IOUtils.toByteArray(newUri)), is(newHash));
+ }
+ @Test
+ public void varyMvcResponse() throws Exception {
+ mockMvc.perform(get("/"))
+ .andExpect(status().isOk())
+ .andExpect(header().string("Vary", "Accept-Language"));
+ mockMvc.perform(get("/rss/ugnich/blog"))
+ .andExpect(status().isOk())
+ .andExpect(header().string("Vary", "Accept-Language"));
+ mockMvc.perform(get("/api/messages"))
+ .andExpect(status().isOk())
+ .andExpect(header().string("Vary", "Accept-Language"));
+ }
+ @Test
+ public void apiInfo() throws Exception {
+ userService.createUser("tst", "tst");
+ MvcResult result = mockMvc.perform(get("/api/info/tst"))
+ .andExpect(status().isOk())
+ .andReturn();
+ User tst = jsonMapper.readValue(result.getResponse().getContentAsString(), User.class);
+ assertThat(tst.getReaders(), is(nullValue()));
+ commandsManager.processCommand(ugnich, "S @tst", emptyUri);
+ result = mockMvc.perform(get("/api/info/tst"))
+ .andExpect(status().isOk())
+ .andReturn();
+ tst = jsonMapper.readValue(result.getResponse().getContentAsString(), User.class);
+ assertThat(tst.getReaders().size(), is(1));
+ }
+ @Test
+ public void federatedUserDeletionFlow() throws Exception {
+ String deleteJsonStr = IOUtils.toString(new ClassPathResource("delete_user.json").getURI(), StandardCharsets.UTF_8);
+ Delete delete = jsonMapper.readValue(deleteJsonStr, Delete.class);
+ ClientHttpRequestFactory originalRequestFactory = apClient.getRequestFactory();
+ MockRestServiceServer restServiceServer = MockRestServiceServer.createServer(apClient);
+ restServiceServer.expect(times(2), requestTo((String) delete.getObject()))
+ .andRespond(withStatus(HttpStatus.GONE));
+ restServiceServer.expect(requestTo((String) delete.getObject()))
+ .andRespond(response -> {
+ throw new ResourceAccessException("Connection reset");
+ });
+ mockMvc.perform(post("/api/inbox")
+ .contentType(ACTIVITY_MEDIA_TYPE)
+ .content(deleteJsonStr))
+ .andExpect(status().isAccepted());
+ mockMvc.perform(post("/api/inbox")
+ .contentType(ACTIVITY_MEDIA_TYPE)
+ .content(deleteJsonStr)
+ .header("Signature", "keyId=\"https://example.com/users/deleted#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"wHoU91JJBsIYcR1W1/57B0oG98t5Aa/TvGPw1B8KQlAp5KhpePnOzD1MZRgivBx7YKO6eYwDx+AX9dn6tjlAvzRLygv21H6UoDZFihWzeE1HM8pY2Pe4EhUgYBN0YuiKUi7W4TS9bDRAJ5vGNPUWATe+2o5Jcbux5cZYXFKKYbLBLD+/IlqPdHA2IXLZ52HFVVfBkPH5sSklV6XJtD/PHLK9R/I9w/mUpj9moUPQu44rR7KvxiGNuHla3vfDtJbkBqLMdScX91EG8373AulXPUiCCF7R2lJB0fFQedm2nSbcwBoJ32GEyOyOPFgPKG5zd9Fd5TfB1pmA8ZIE0sChfA==\""))
+ .andExpect(status().isAccepted());
+ apClient.setRequestFactory(originalRequestFactory);
+ }
+ @Test
+ public void handleIncorrectCertificates() throws Exception {
+ String deleteJsonStr = IOUtils.toString(new ClassPathResource("delete_user.json").getURI(), StandardCharsets.UTF_8);
+ Delete delete = jsonMapper.readValue(deleteJsonStr, Delete.class);
+ ClientHttpRequestFactory originalRequestFactory = apClient.getRequestFactory();
+ MockRestServiceServer restServiceServer = MockRestServiceServer.createServer(apClient);
+ restServiceServer.expect(requestTo((String) delete.getObject()))
+ .andRespond(response -> {
+ throw new ResourceAccessException("Connection reset");
+ });
+ mockMvc.perform(post("/api/inbox")
+ .contentType(ACTIVITY_MEDIA_TYPE)
+ .content(deleteJsonStr)
+ .header("Signature", "keyId=\"https://example.com/users/deleted#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"wHoU91JJBsIYcR1W1/57B0oG98t5Aa/TvGPw1B8KQlAp5KhpePnOzD1MZRgivBx7YKO6eYwDx+AX9dn6tjlAvzRLygv21H6UoDZFihWzeE1HM8pY2Pe4EhUgYBN0YuiKUi7W4TS9bDRAJ5vGNPUWATe+2o5Jcbux5cZYXFKKYbLBLD+/IlqPdHA2IXLZ52HFVVfBkPH5sSklV6XJtD/PHLK9R/I9w/mUpj9moUPQu44rR7KvxiGNuHla3vfDtJbkBqLMdScX91EG8373AulXPUiCCF7R2lJB0fFQedm2nSbcwBoJ32GEyOyOPFgPKG5zd9Fd5TfB1pmA8ZIE0sChfA==\""))
+ .andExpect(status().isAccepted());
+ apClient.setRequestFactory(originalRequestFactory);
+ }
+
+ @Test
+ public void legacyAvatarEndpoint() throws Exception {
+ mockMvc.perform(get("/api/avatar")
+ .param("uname", "unknown"))
+ .andExpect(status().isOk())
+ .andExpect(content().bytes(IOUtils.toByteArray(defaultAvatar.getInputStream())));
+ }
+ @Test
+ public void federatedAttachmentsAsLinks() throws Exception {
+ int mid = messagesService.createMessage(ugnich.getUid(), "test", StringUtils.EMPTY, Collections.emptyList());
+ Message testMessage = MockUtils.mockMessage(mid, freefd, "reply");
+ String activity = IOUtils.toString(noteWithDocument.getInputStream(), StandardCharsets.UTF_8);
+ Announce announce = jsonMapper.readValue(activity, Announce.class);
+ }
+ @Test
+ public void hubzillaActor() throws Exception {
+ String activity = IOUtils.toString(hubzillaActivity.getInputStream(), StandardCharsets.UTF_8);
+ Create create = jsonMapper.readValue(activity, Create.class);
+ String followData = IOUtils.toString(hubzillaFollow.getInputStream(), StandardCharsets.UTF_8);
+ Follow follow = jsonMapper.readValue(followData, Follow.class);
+ assertThat(follow.getActor(), is("https://ussr.win/channel/zlax"));
+ }
+ @Test
+ public void nodeinfo() throws Exception {
+ MvcResult nodeinfoXRD = mockMvc.perform(get("/.well-known/nodeinfo")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andReturn();
+ JsonNode node = jsonMapper.readTree(nodeinfoXRD.getResponse().getContentAsString());
+ assertThat(node.get("links"), notNullValue());
+ String nodeinfoUrl = node.get("links").get(0).get("href").textValue();
+ MvcResult nodeinfoData = mockMvc.perform(get(nodeinfoUrl)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andReturn();
+ JsonNode nodeinfo = jsonMapper.readTree(nodeinfoData.getResponse().getContentAsString());
+ assertThat(nodeinfo.get("software"), notNullValue());
+ assertThat(nodeinfo.get("server"), nullValue());
+ MvcResult xnodeinfoData = mockMvc.perform(get("/.well-known/x-nodeinfo2")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andReturn();
+ JsonNode xnodeinfo = jsonMapper.readTree(xnodeinfoData.getResponse().getContentAsString());
+ assertThat(xnodeinfo.get("server"), notNullValue());
+ assertThat(xnodeinfo.get("software"), nullValue());
+ }
+ @Test
+ public void anonymousUserFromZero() {
+ User user = userService.getUserByUID(0).orElse(AnonymousUser.INSTANCE);
+ assertThat(user.isAnonymous(), is(true));
+ }
}
diff --git a/src/test/java/com/juick/test/util/MockUtils.java b/src/test/java/com/juick/test/util/MockUtils.java
index 017af4d1..8f6b821d 100644
--- a/src/test/java/com/juick/test/util/MockUtils.java
+++ b/src/test/java/com/juick/test/util/MockUtils.java
@@ -34,7 +34,7 @@ public class MockUtils {
msg.setMid(mid);
msg.setUser(user);
msg.setText(messageText == null ? generator.generate(24) : messageText);
- msg.setTimestamp(Instant.now());
+ msg.setCreated(Instant.now());
return msg;
}
diff --git a/src/test/resources/2936611-57.jpg b/src/test/resources/2936611-57.jpg
new file mode 100644
index 00000000..af4f9c91
--- /dev/null
+++ b/src/test/resources/2936611-57.jpg
Binary files differ
diff --git a/src/test/resources/announce.json b/src/test/resources/announce.json
new file mode 100644
index 00000000..4ae4a2ad
--- /dev/null
+++ b/src/test/resources/announce.json
@@ -0,0 +1 @@
+{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","sensitive":"as:sensitive","movedTo":{"@id":"as:movedTo","@type":"@id"},"alsoKnownAs":{"@id":"as:alsoKnownAs","@type":"@id"},"Hashtag":"as:Hashtag","ostatus":"http://ostatus.org#","atomUri":"ostatus:atomUri","inReplyToAtomUri":"ostatus:inReplyToAtomUri","conversation":"ostatus:conversation","toot":"http://joinmastodon.org/ns#","Emoji":"toot:Emoji","focalPoint":{"@container":"@list","@id":"toot:focalPoint"},"featured":{"@id":"toot:featured","@type":"@id"},"schema":"http://schema.org#","PropertyValue":"schema:PropertyValue","value":"schema:value"}],"id":"https://mastodon.social/users/armitage/statuses/101641036945418885/activity","type":"Announce","actor":"https://mastodon.social/users/armitage","published":"2019-02-23T10:52:22Z","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://juick.com/u/netneladno","https://mastodon.social/users/armitage/followers"],"atomUri":"https://mastodon.social/users/armitage/statuses/101641036945418885/activity","object":{"id":"https://juick.com/n/2936427-0","type":"Note","summary":null,"inReplyTo":null,"published":"2019-02-23T10:13:59Z","url":"https://juick.com/m/2936427","attributedTo":"https://juick.com/u/netneladno","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://mastodon.social/users/netneladno/followers"],"sensitive":false,"atomUri":null,"inReplyToAtomUri":null,"conversation":"tag:mastodon.social,2019-02-23:objectId=86866293:objectType=Conversation","content":"\u003cp\u003e\u003c/p\u003e\n","attachment":[{"type":"Document","mediaType":"image/jpeg","url":"https://i.juick.com/photos-1024/2936427.jpg","name":null}],"tag":[]},"signature":{"type":"RsaSignature2017","creator":"https://mastodon.social/users/armitage#main-key","created":"2019-02-23T10:52:22Z","signatureValue":"hEbN5wumGY98T/t5ZbgBLxQNEHX6PJgO9dGwIdTq0T+GJ518J3duhHlhljBQkGgnH/68aSBWHxDQ+57YRVlR6lukvl0hKCg8Rx1NOYhtU+9OH//MH2uMt/XXh2pE1dv+RVA7GS4zkCMjKKMhY6WNzbJQS4FfvaCmmEn6gqiCSXbo1lLo4bkhBRyfpAH8Z9Z8/wEbRAl0qCVZlim8ELOZ8rWVfnmgF3gGDWwpgzSEqIbxEytpHtNeYC+ZC3FVlxMAomvxuyj2XCv6B854ol5UQ30O8MLVNiTCoUa/7w6k/I3pmN1etpJ53XD8Si0Qg6QKHO8R3Wp6S9LSoF0Hj/GiDQ=="}} \ No newline at end of file
diff --git a/src/test/resources/data.sql b/src/test/resources/data.sql
index 102b11f4..aff3e286 100644
--- a/src/test/resources/data.sql
+++ b/src/test/resources/data.sql
@@ -1,3 +1,4 @@
+INSERT INTO users(id, nick, passw) VALUES(0, 'Anonymous', 'password');
INSERT INTO tags(tag_id, name) VALUES(2, 'juick');
INSERT INTO reactions (like_id, description) VALUES (1, 'like');
INSERT INTO reactions (like_id, description) VALUES (2, 'love');
diff --git a/src/test/resources/delete_user.json b/src/test/resources/delete_user.json
new file mode 100644
index 00000000..b68db011
--- /dev/null
+++ b/src/test/resources/delete_user.json
@@ -0,0 +1 @@
+{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","sensitive":"as:sensitive","movedTo":{"@id":"as:movedTo","@type":"@id"},"alsoKnownAs":{"@id":"as:alsoKnownAs","@type":"@id"},"Hashtag":"as:Hashtag","ostatus":"http://ostatus.org#","atomUri":"ostatus:atomUri","inReplyToAtomUri":"ostatus:inReplyToAtomUri","conversation":"ostatus:conversation","toot":"http://joinmastodon.org/ns#","Emoji":"toot:Emoji","focalPoint":{"@container":"@list","@id":"toot:focalPoint"},"featured":{"@id":"toot:featured","@type":"@id"},"schema":"http://schema.org#","PropertyValue":"schema:PropertyValue","value":"schema:value"}],"id":"https://example.com/users/deleted#delete","type":"Delete","actor":"https://example.com/users/deleted","to":["https://www.w3.org/ns/activitystreams#Public"],"object":"https://example.com/users/deleted","signature":{"type":"RsaSignature2017","creator":"https://mastodon.social/users/andoniserra#main-key","created":"2019-01-29T14:50:13Z","signatureValue":"svq8NDQeXb0widXDL1jygye+a536L4GFPTT+8euXgdHhzij6y5dIpT+s0I0ZheAIfHEe+k3N5XysQMvJ4Jmh8douWZ14DkZNai5luk4Ftg5v/RynYAY65UgsldTf9XUvAbSiRGAK4s2b8qE3zsQihEHRIUrzb2bgvhKUkr8FuuuNDDDSS9i9bxnzQp8DSVivqdW2zJYm3ARtW7sWKSXoSaiP2KxIfRPC6UdDDSFbRr3zHckxRjsPnfWr8VvhjxggzVYcp4ZIJDqJj0qoy1lyRIRTWaDJwZIjFX7JjE5OVoKBt++IcY6IARpTGVxV4GXeeFMB7/y1tMaZoold6VlqyQ=="}} \ No newline at end of file
diff --git a/src/test/resources/hubzilla_activity.json b/src/test/resources/hubzilla_activity.json
new file mode 100644
index 00000000..b25aca87
--- /dev/null
+++ b/src/test/resources/hubzilla_activity.json
@@ -0,0 +1,185 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ "https://ussr.win/apschema/v1.2"
+ ],
+ "type": "Create",
+ "id": "https://ussr.win/activity/e46a6100e4ba83d602eab5fe0e035405a32d7d36094c95dc85c5c9fcd3d93ab2%40ussr.win",
+ "published": "2019-02-14T11:23:29Z",
+ "updated": "2019-02-14T11:38:48Z",
+ "actor": {
+ "type": "Person",
+ "id": "https://ussr.win/channel/zlax",
+ "preferredUsername": "zlax",
+ "name": "ivan zlax",
+ "icon": {
+ "type": "Image",
+ "mediaType": "image/jpeg",
+ "url": "https://ussr.win/photo/profile/l/2",
+ "height": 300,
+ "width": 300
+ },
+ "url": {
+ "type": "Link",
+ "mediaType": "text/html",
+ "href": "https://ussr.win/channel/zlax"
+ },
+ "inbox": "https://ussr.win/inbox/zlax",
+ "outbox": "https://ussr.win/outbox/zlax",
+ "followers": "https://ussr.win/followers/zlax",
+ "following": "https://ussr.win/following/zlax",
+ "endpoints": {
+ "sharedInbox": "https://ussr.win/inbox"
+ },
+ "publicKey": {
+ "id": "https://ussr.win/channel/zlax/public_key_pem",
+ "owner": "https://ussr.win/channel/zlax",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtFSIKFVzo+9NzzY0xho9\nA8CqO0j12f3HEOZUDBDj1NBbQ6Cj1p1f5mB1AlRr+a05fqpraCWIJyCXVTtdyjem\niQ/ObT2PuZIhAY04/ptv78S9EM9ImZi2aDNWp2nWQu23dJajb2TMpIxGNS1M3DVR\ngXwRVEVIEEDzftWx7vF4335/2uJvPfwTzKI3pR972xp1iZCd/G3BtYzUW4swIFSu\n+5ZLKhgwO6A4Ge5+sn2k6x+K56YCgeEEQheOg+PbggIQ68xfvYCQyfuShqAXEadv\nOvQ1dN8WO+tgKqYDRQgILIONB8/2/XXMoQbSVRZs2GmLKXHhIeVKiSZ1vKwHsPx1\nCYUayQo/BB1JpbjkmyDQcHAX+KZ7PQUhpQn976f6Ycp5rznvBH5Zm96VKySaGMy7\nGWefafOfcCNfVZpq17gPPfSbC0XOHdvm6T1e1OPwFl/ho9HxatbA60DIDEd7xf4V\nq9aTSZ2MeQW5JXaxJXSgwucPZ9mhVfucFtCyLdlHZ7gA5yJ+pyYmMe8pjCSNWztD\nUOoJC46vv2l1RbMGTJy2AY9ZuPvyrmJHlsRsTYcmDYRFSk6sgGi1eswSDHlruE3u\nKG4E0nsA8qxzgzpCViQV4DIgXhMInBwo7ZhSyWD+tF2a4tpXorHqmg35x/aqJlaq\nE2xF+yrfh/Kx8O+7P6C1aGcCAwEAAQ==\n-----END PUBLIC KEY-----\n"
+ },
+ "nomadicLocations": [
+ {
+ "id": "https://ussr.win/locs/zlax",
+ "type": "nomadicLocation",
+ "locationAddress": "acct:zlax@ussr.win",
+ "locationPrimary": true,
+ "locationDeleted": false
+ }
+ ]
+ },
+ "object": {
+ "type": "Note",
+ "id": "https://ussr.win/item/e46a6100e4ba83d602eab5fe0e035405a32d7d36094c95dc85c5c9fcd3d93ab2%40ussr.win",
+ "published": "2019-02-14T11:23:29Z",
+ "updated": "2019-02-14T11:38:48Z",
+ "url": {
+ "type": "text/html",
+ "rel": "alternate",
+ "href": "https://ussr.win/channel/zlax/?f=&mid=e46a6100e4ba83d602eab5fe0e035405a32d7d36094c95dc85c5c9fcd3d93ab2@ussr.win"
+ },
+ "attributedTo": "https://ussr.win/channel/zlax",
+ "content": "<span class=\"bookmark-identifier\">#^</span><a class=\"bookmark\" href=\"https://twitter.com/Dalatrm/status/1095677403198906369\" target=\"_blank\" rel=\"nofollow noopener\" >https://twitter.com/Dalatrm/status/1095677403198906369</a><br /><span class=\"bookmark-identifier\">#^</span><a class=\"bookmark\" href=\"https://twitter.com/Dalatrm/status/1095677401433022466\" target=\"_blank\" rel=\"nofollow noopener\" >https://twitter.com/Dalatrm/status/1095677401433022466</a><br /><img class=\"zrl\" src=\"https://ussr.win/photo/6776e315a9692860af53c19518e524f50ab047a4317435403532c922a7c484d4-2.jpg\" style=\"width: 100%; max-width: 590px;\" alt=\"Image/photo\" /><br /><br /><img class=\"zrl\" src=\"https://ussr.win/photo/afb21af40be39ad19589dec5dfa0161b2364b59331bba95aae823e68b3acfbf3-2.jpg\" style=\"width: 100%; max-width: 623px;\" alt=\"Image/photo\" /><br />Продюсер BBC признал постановочными сцены после химатаки в Сирии<br /><span class=\"bookmark-identifier\">#^</span><a class=\"bookmark\" href=\"https://www.vedomosti.ru/politics/news/2019/02/14/794104-bbc-himataki\" target=\"_blank\" rel=\"nofollow noopener\" >https://www.vedomosti.ru/politics/news/2019/02/14/794104-bbc-himataki</a><br /><blockquote>Сцены в госпитале сирийского города Дума после предполагаемой химической атаки были постановочными для достижения «максимального эффекта». Об этом в своем твиттере написал продюсер BBC по Сирии Риам Далати. «Спустя почти шесть месяцев расследования я могу подтвердить без тени сомнения, что сцены в госпитале Думы были постановочные. Погибших в больнице не было», — признал он.<br /><br />Сам факт химической атаки, якобы имевшей место 7 апреля 2018 г., пока не подтвержден Организацией по запрещению химического оружия (ОЗХО). «Атака была, зарин не использовался, но мы должны дождаться, когда ОЗХО подтвердит, использовался ли хлор или что-то еще. Однако все остальное вокруг атаки было создано для максимального эффекта», — написал Далати.<br /><br />Информацию о применении в сирийской Думе химического оружия с использованием хлора и нервно-паралитического агента распространили общественные организации, в том числе «Белые каски». По данным организации, жертвами атаки стали около 70 человек.</blockquote><br />#<a class=\"zrl\" href=\"https://ussr.win/search?tag=bbc\" target=\"_blank\" rel=\"nofollow noopener\" >bbc</a> #<a class=\"zrl\" href=\"https://ussr.win/search?tag=capitalism\" target=\"_blank\" rel=\"nofollow noopener\" >capitalism</a> #<a class=\"zrl\" href=\"https://ussr.win/search?tag=conspiracy\" target=\"_blank\" rel=\"nofollow noopener\" >conspiracy</a> #<a class=\"zrl\" href=\"https://ussr.win/search?tag=history\" target=\"_blank\" rel=\"nofollow noopener\" >history</a> #<a class=\"zrl\" href=\"https://ussr.win/search?tag=hoax\" target=\"_blank\" rel=\"nofollow noopener\" >hoax</a> #<a class=\"zrl\" href=\"https://ussr.win/search?tag=metaprogramming\" target=\"_blank\" rel=\"nofollow noopener\" >metaprogramming</a> #<a class=\"zrl\" href=\"https://ussr.win/search?tag=revision\" target=\"_blank\" rel=\"nofollow noopener\" >revision</a> #<a class=\"zrl\" href=\"https://ussr.win/search?tag=syria\" target=\"_blank\" rel=\"nofollow noopener\" >syria</a> #<a class=\"zrl\" href=\"https://ussr.win/search?tag=terrorism\" target=\"_blank\" rel=\"nofollow noopener\" >terrorism</a> #<a class=\"zrl\" href=\"https://ussr.win/search?tag=uk\" target=\"_blank\" rel=\"nofollow noopener\" >uk</a> #<a class=\"zrl\" href=\"https://ussr.win/search?tag=war\" target=\"_blank\" rel=\"nofollow noopener\" >war</a> #<a class=\"zrl\" href=\"https://ussr.win/search?tag=whitehelments\" target=\"_blank\" rel=\"nofollow noopener\" >whitehelments</a>",
+ "actor": {
+ "type": "Person",
+ "id": "https://ussr.win/channel/zlax",
+ "preferredUsername": "zlax",
+ "name": "ivan zlax",
+ "icon": {
+ "type": "Image",
+ "mediaType": "image/jpeg",
+ "url": "https://ussr.win/photo/profile/l/2",
+ "height": 300,
+ "width": 300
+ },
+ "url": {
+ "type": "Link",
+ "mediaType": "text/html",
+ "href": "https://ussr.win/channel/zlax"
+ },
+ "inbox": "https://ussr.win/inbox/zlax",
+ "outbox": "https://ussr.win/outbox/zlax",
+ "followers": "https://ussr.win/followers/zlax",
+ "following": "https://ussr.win/following/zlax",
+ "endpoints": {
+ "sharedInbox": "https://ussr.win/inbox"
+ },
+ "publicKey": {
+ "id": "https://ussr.win/channel/zlax/public_key_pem",
+ "owner": "https://ussr.win/channel/zlax",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtFSIKFVzo+9NzzY0xho9\nA8CqO0j12f3HEOZUDBDj1NBbQ6Cj1p1f5mB1AlRr+a05fqpraCWIJyCXVTtdyjem\niQ/ObT2PuZIhAY04/ptv78S9EM9ImZi2aDNWp2nWQu23dJajb2TMpIxGNS1M3DVR\ngXwRVEVIEEDzftWx7vF4335/2uJvPfwTzKI3pR972xp1iZCd/G3BtYzUW4swIFSu\n+5ZLKhgwO6A4Ge5+sn2k6x+K56YCgeEEQheOg+PbggIQ68xfvYCQyfuShqAXEadv\nOvQ1dN8WO+tgKqYDRQgILIONB8/2/XXMoQbSVRZs2GmLKXHhIeVKiSZ1vKwHsPx1\nCYUayQo/BB1JpbjkmyDQcHAX+KZ7PQUhpQn976f6Ycp5rznvBH5Zm96VKySaGMy7\nGWefafOfcCNfVZpq17gPPfSbC0XOHdvm6T1e1OPwFl/ho9HxatbA60DIDEd7xf4V\nq9aTSZ2MeQW5JXaxJXSgwucPZ9mhVfucFtCyLdlHZ7gA5yJ+pyYmMe8pjCSNWztD\nUOoJC46vv2l1RbMGTJy2AY9ZuPvyrmJHlsRsTYcmDYRFSk6sgGi1eswSDHlruE3u\nKG4E0nsA8qxzgzpCViQV4DIgXhMInBwo7ZhSyWD+tF2a4tpXorHqmg35x/aqJlaq\nE2xF+yrfh/Kx8O+7P6C1aGcCAwEAAQ==\n-----END PUBLIC KEY-----\n"
+ },
+ "nomadicLocations": [
+ {
+ "id": "https://ussr.win/locs/zlax",
+ "type": "nomadicLocation",
+ "locationAddress": "acct:zlax@ussr.win",
+ "locationPrimary": true,
+ "locationDeleted": false
+ }
+ ]
+ },
+ "tag": [
+ {
+ "id": "https://ussr.win/search?tag=metaprogramming",
+ "name": "#metaprogramming"
+ },
+ {
+ "id": "https://ussr.win/search?tag=whitehelments",
+ "name": "#whitehelments"
+ },
+ {
+ "id": "https://ussr.win/search?tag=capitalism",
+ "name": "#capitalism"
+ },
+ {
+ "id": "https://ussr.win/search?tag=conspiracy",
+ "name": "#conspiracy"
+ },
+ {
+ "id": "https://ussr.win/search?tag=terrorism",
+ "name": "#terrorism"
+ },
+ {
+ "id": "https://ussr.win/search?tag=revision",
+ "name": "#revision"
+ },
+ {
+ "id": "https://ussr.win/search?tag=history",
+ "name": "#history"
+ },
+ {
+ "id": "https://ussr.win/search?tag=syria",
+ "name": "#syria"
+ },
+ {
+ "id": "https://ussr.win/search?tag=hoax",
+ "name": "#hoax"
+ },
+ {
+ "id": "https://ussr.win/search?tag=bbc",
+ "name": "#bbc"
+ },
+ {
+ "id": "https://ussr.win/search?tag=war",
+ "name": "#war"
+ },
+ {
+ "id": "https://ussr.win/search?tag=uk",
+ "name": "#uk"
+ }
+ ],
+ "attachment": [
+ {
+ "type": "Image",
+ "url": "https://ussr.win/photo/6776e315a9692860af53c19518e524f50ab047a4317435403532c922a7c484d4-2.jpg"
+ },
+ {
+ "type": "Image",
+ "url": "https://ussr.win/photo/afb21af40be39ad19589dec5dfa0161b2364b59331bba95aae823e68b3acfbf3-2.jpg"
+ }
+ ],
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://ussr.win/followers/zlax"
+ ]
+ },
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://ussr.win/followers/zlax"
+ ],
+ "signature": {
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1"
+ ],
+ "type": "RsaSignature2017",
+ "nonce": "c4f8b31f4277d4322a528697d550aefd78a4a7709f0da25285032f7529d3f550",
+ "creator": "https://ussr.win/channel/zlax/public_key_pem",
+ "created": "2019-02-14T11:39:01Z",
+ "signatureValue": "WnXFcSm3nR1Su4QwSVJq6vQ7xdtPQTfs5iTMcAcxasoGHphJaAZRISV1QRPuMhw5jap4Lmb4ZaFRfqGm4M4HND+mI06dC2HlgCh0vnNvGsbcDa2RybSnIUo/xswEa/Mcpf6uy2dcLwaZY6tXOkkJmtZOseN54CUO3bQHbd3KmSiqkvREMXv2+qrVJhohZ4R9tLXamUTkoJmq1wSS2s8XSUlmO2v+Th3OAEoHeiS1SehglvIzua83IKlU2/iAs8akGVyYng5uLO7YeUsmiKHggef1ss8XKcNuhaAW8b3DUTnUwBZCPiiCoeXEQMfYdciCtTAKARHLr5RlHPE7etf1Fqk9Pozo/b2EDpfTxbZ26ZKY02pl4g82u95L43hTmCLbZ+wbKt5M0uHRld+/WkJrkIVS2Vj0MJ84Pp94Ij5A0MaXnBDiIj8YpvbRWWVEdXWKs/N8Dy0c11NiHCPhurZTMQDwv96bBphLQGlTp4USYjbKlS95JyyxbfjRbbubM4Q3MGsZFWbRi7C0exvZiw8zHBGn3hnbnZsDdlDax2weuXsSzHPlw8DxG6XEXZy3GWuK4LlQCVXaa9AcSd9LODVIrxaelr0pdW38a2rot1rlkGHdYPR8oD5zV3fj4kWs3n68mU9VJRTvubbX1zKV8EIX9UvVJ6wuRHqyVOFKJPkKloc="
+ }
+} \ No newline at end of file
diff --git a/src/test/resources/hubzilla_follow.json b/src/test/resources/hubzilla_follow.json
new file mode 100644
index 00000000..fff33c36
--- /dev/null
+++ b/src/test/resources/hubzilla_follow.json
@@ -0,0 +1 @@
+{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1","https://ussr.win/apschema/v1.3"],"id":"https://ussr.win/follow/1216","type":"Follow","actor":{"type":"Person","id":"https://ussr.win/channel/zlax","preferredUsername":"zlax","name":"ivan zlax","icon":{"type":"Image","mediaType":"image/jpeg","url":"https://ussr.win/photo/profile/l/2","height":300,"width":300},"url":{"type":"Link","mediaType":"text/html","href":"https://ussr.win/channel/zlax"},"inbox":"https://ussr.win/inbox/zlax","outbox":"https://ussr.win/outbox/zlax","followers":"https://ussr.win/followers/zlax","following":"https://ussr.win/following/zlax","endpoints":{"sharedInbox":"https://ussr.win/inbox"},"publicKey":{"id":"https://ussr.win/channel/zlax/public_key_pem","owner":"https://ussr.win/channel/zlax","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtFSIKFVzo+9NzzY0xho9\nA8CqO0j12f3HEOZUDBDj1NBbQ6Cj1p1f5mB1AlRr+a05fqpraCWIJyCXVTtdyjem\niQ/ObT2PuZIhAY04/ptv78S9EM9ImZi2aDNWp2nWQu23dJajb2TMpIxGNS1M3DVR\ngXwRVEVIEEDzftWx7vF4335/2uJvPfwTzKI3pR972xp1iZCd/G3BtYzUW4swIFSu\n+5ZLKhgwO6A4Ge5+sn2k6x+K56YCgeEEQheOg+PbggIQ68xfvYCQyfuShqAXEadv\nOvQ1dN8WO+tgKqYDRQgILIONB8/2/XXMoQbSVRZs2GmLKXHhIeVKiSZ1vKwHsPx1\nCYUayQo/BB1JpbjkmyDQcHAX+KZ7PQUhpQn976f6Ycp5rznvBH5Zm96VKySaGMy7\nGWefafOfcCNfVZpq17gPPfSbC0XOHdvm6T1e1OPwFl/ho9HxatbA60DIDEd7xf4V\nq9aTSZ2MeQW5JXaxJXSgwucPZ9mhVfucFtCyLdlHZ7gA5yJ+pyYmMe8pjCSNWztD\nUOoJC46vv2l1RbMGTJy2AY9ZuPvyrmJHlsRsTYcmDYRFSk6sgGi1eswSDHlruE3u\nKG4E0nsA8qxzgzpCViQV4DIgXhMInBwo7ZhSyWD+tF2a4tpXorHqmg35x/aqJlaq\nE2xF+yrfh/Kx8O+7P6C1aGcCAwEAAQ==\n-----END PUBLIC KEY-----\n"},"nomadicLocations":[{"id":"https://ussr.win/locs/zlax","type":"nomadicLocation","locationAddress":"acct:zlax@ussr.win","locationPrimary":true,"locationDeleted":false}]},"object":"https://juick.com/u/netneladno","to":["https://juick.com/u/netneladno"],"signature":{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1"],"type":"RsaSignature2017","nonce":"1ee5df16edb30d1944fcb07859849ee4293da98c13322c13e2f929b822da91a7","creator":"https://ussr.win/channel/zlax/public_key_pem","created":"2019-02-23T11:09:56Z","signatureValue":"M6551dhNfk0vsSQ6hYvxXVURb7NviNk8ExYBLsax6uYr1oyV/zQJuUtoqufr47t/2NvfzLVn0criLAKbF586siIFd2YBO4wPWtSDPPAWgaQxDrCzRG4PimuavgT0ghIKzmmMnCG6BLC4O0+ohKPUFzaOHgsgdM++TY21OdLQUaauwYkvn9eWYGXzkS5LEnxEKuFpQarOtzChpP9btI9P3iDDRaOqTTlDw0w1xZ8/LqqPCqoA5W8NS+xSyhHsvFi1ApNinFQNM5+e1Gj09Lvtumn2rQE9Smn8sXG9jp5MSBKFdmuG20PDqidfQ3uvZm5qPdwfJnWjZ2VD00aOSji3ahcHJWkbxpNQki2TBb6u2FDABPlUsBvJ2Z23Ubdm+kcjNklmlZeAgcTvWoZhlzushlGjukRwMymRJZXQNIAgVoKbWhvm2w8NX1cQWs1XS211IPl44sT33T5ZoDNMiDPru+XtHWXrZxA2jpLrHec18bZ15y66KTi67s8QNoYn7cUSqETtch7Vuixw2oxQZNfDj0yhthbi7+lFoqB1Ilo37rJx/9wMY9O271n4rBmuSoHmMDVUSZBZxPjpzvm3zS/NjxczwNJ8a8hZSGcDvViHf2Lcqj+qt+DBbI1jtPGRTieR6pVRjxa7MjjZipDMhYczn13poKQ4KK3lYakyaNhjgHg="}} \ No newline at end of file
diff --git a/src/test/resources/mocks/activity/testfollow.json b/src/test/resources/mocks/activity/testfollow.json
new file mode 100644
index 00000000..e308e52e
--- /dev/null
+++ b/src/test/resources/mocks/activity/testfollow.json
@@ -0,0 +1,15 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "schema": "http://schema.org#",
+ "PropertyValue": "schema:PropertyValue",
+ "value": "schema:value"
+ }
+ ],
+ "id": "https://example.com/12345678",
+ "type": "Follow",
+ "actor": "https://example.com/u/testuser",
+ "object": "http://localhost:8080/u/ugnich"
+} \ No newline at end of file
diff --git a/src/test/resources/mocks/activity/testuser.json b/src/test/resources/mocks/activity/testuser.json
new file mode 100644
index 00000000..95fc2aa9
--- /dev/null
+++ b/src/test/resources/mocks/activity/testuser.json
@@ -0,0 +1,27 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "schema": "http://schema.org#",
+ "PropertyValue": "schema:PropertyValue",
+ "value": "schema:value"
+ }
+ ],
+ "id": "https://example.com/u/testuser",
+ "type": "Person",
+ "following": "https://example.com/u/testuser/following",
+ "followers": "https://example.com/u/testuser/followers",
+ "inbox": "https://example.com/u/testuser/inbox",
+ "outbox": "https://example.com/u/testuser/outbox",
+ "preferredUsername": "testuser",
+ "url": "https://example.com/@testuser",
+ "publicKey": {
+ "id": "https://example.com/u/testuser#main-key",
+ "owner": "https://example.com/u/testuser",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiHKRdKFFeT4P/MVlNbxC\nbbgXOkEdeQzvJB/wAJgSYbUwm9SzNFzttePQXk3/MWoK2awWUInZTduVHsWt8zU7\nO3d9PAW6YH6L1oDkjgMLAb9aUWV2ClQWMwsn88WKK9Rb1WOmd8BrXjPfmeFK2ypQ\n9eg8aKpH36WAXiiaTDfBupBZ0Ki2+E87BrWxpbUeDC1dkV+zbl8BMm7X0rp+reoC\nYUWMcjQMzhMmQOXUd4zwJIDPZDMdF4beq/y6WPSUTVgjs4kPDS1HT60ATnsUqyPE\n6tuGxG4j0msb4TTre87PKxMU5YPOxSiqNL0O/3u9/2shVPpjDa/uy9W+VaeBHbFm\nSQIDAQAB\n-----END PUBLIC KEY-----\n"
+ },
+ "endpoints": {
+ "sharedInbox": "https://example.com/inbox"
+ }
+} \ No newline at end of file
diff --git a/src/test/resources/test.p12 b/src/test/resources/test.p12
new file mode 100644
index 00000000..7f7457eb
--- /dev/null
+++ b/src/test/resources/test.p12
Binary files differ
diff --git a/webpack.config.js b/webpack.config.js
index 18db4ec5..1075a46d 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,5 +1,4 @@
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
-const StyleLintPlugin = require('stylelint-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
@@ -20,6 +19,7 @@ module.exports = (env, argv) => {
'core-js/modules/es6.promise',
'core-js/modules/es6.regexp.split',
'core-js/modules/es6.symbol',
+ 'core-js/modules/es6.weak-map',
'core-js/modules/web.dom.iterable',
'url-polyfill',
'whatwg-fetch',
@@ -47,6 +47,7 @@ module.exports = (env, argv) => {
{
loader: 'postcss-loader', options: {
plugins: () => [
+ require('stylelint')(),
require('postcss-preset-env')()
]
}
@@ -58,7 +59,6 @@ module.exports = (env, argv) => {
]
},
plugins: [
- new StyleLintPlugin({ configFile: '.stylelintrc.json', context: 'src/main/assets', files: ['**/*.css'], emitErrors: false }),
new MiniCssExtractPlugin({ filename: 'style.css', allChunks: true })
],
};
diff --git a/yarn.lock b/yarn.lock
index 486f2023..123ad740 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9,42 +9,42 @@
dependencies:
"@babel/highlight" "^7.0.0"
-"@babel/core@^7.1.2":
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.1.2.tgz#f8d2a9ceb6832887329a7b60f9d035791400ba4e"
- integrity sha512-IFeSSnjXdhDaoysIlev//UzHZbdEmm7D0EIH2qtse9xK7mXEZQpYjs2P00XlP1qYsYvid79p+Zgg6tz1mp6iVw==
+"@babel/core@>=7.1.0":
+ version "7.2.2"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.2.2.tgz#07adba6dde27bb5ad8d8672f15fde3e08184a687"
+ integrity sha512-59vB0RWt09cAct5EIe58+NzGP4TFSD3Bz//2/ELy3ZeTeKF6VTD1AXlH8BGGbCX0PuobZBsIzO7IAI9PH67eKw==
dependencies:
"@babel/code-frame" "^7.0.0"
- "@babel/generator" "^7.1.2"
- "@babel/helpers" "^7.1.2"
- "@babel/parser" "^7.1.2"
- "@babel/template" "^7.1.2"
- "@babel/traverse" "^7.1.0"
- "@babel/types" "^7.1.2"
+ "@babel/generator" "^7.2.2"
+ "@babel/helpers" "^7.2.0"
+ "@babel/parser" "^7.2.2"
+ "@babel/template" "^7.2.2"
+ "@babel/traverse" "^7.2.2"
+ "@babel/types" "^7.2.2"
convert-source-map "^1.1.0"
- debug "^3.1.0"
- json5 "^0.5.0"
+ debug "^4.1.0"
+ json5 "^2.1.0"
lodash "^4.17.10"
resolve "^1.3.2"
semver "^5.4.1"
source-map "^0.5.0"
-"@babel/core@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.2.0.tgz#a4dd3814901998e93340f0086e9867fefa163ada"
- integrity sha512-7pvAdC4B+iKjFFp9Ztj0QgBndJ++qaMeonT185wAqUnhipw8idm9Rv1UMyBuKtYjfl6ORNkgEgcsYLfHX/GpLw==
+"@babel/core@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.4.tgz#921a5a13746c21e32445bf0798680e9d11a6530b"
+ integrity sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==
dependencies:
"@babel/code-frame" "^7.0.0"
- "@babel/generator" "^7.2.0"
+ "@babel/generator" "^7.3.4"
"@babel/helpers" "^7.2.0"
- "@babel/parser" "^7.2.0"
- "@babel/template" "^7.1.2"
- "@babel/traverse" "^7.1.6"
- "@babel/types" "^7.2.0"
+ "@babel/parser" "^7.3.4"
+ "@babel/template" "^7.2.2"
+ "@babel/traverse" "^7.3.4"
+ "@babel/types" "^7.3.4"
convert-source-map "^1.1.0"
debug "^4.1.0"
json5 "^2.1.0"
- lodash "^4.17.10"
+ lodash "^4.17.11"
resolve "^1.3.2"
semver "^5.4.1"
source-map "^0.5.0"
@@ -60,17 +60,6 @@
source-map "^0.5.0"
trim-right "^1.0.1"
-"@babel/generator@^7.1.2":
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.1.2.tgz#fde75c072575ce7abbd97322e8fef5bae67e4630"
- integrity sha512-70A9HWLS/1RHk3Ck8tNHKxOoKQuSKocYgwDN85Pyl/RBduss6AKxUR7RIZ/lzduQMSYfWEM4DDBu6A+XGbkFig==
- dependencies:
- "@babel/types" "^7.1.2"
- jsesc "^2.5.1"
- lodash "^4.17.10"
- source-map "^0.5.0"
- trim-right "^1.0.1"
-
"@babel/generator@^7.1.5":
version "7.1.5"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.1.5.tgz#615f064d13d95f8f9157c7261f68eddf32ec15b3"
@@ -82,25 +71,25 @@
source-map "^0.5.0"
trim-right "^1.0.1"
-"@babel/generator@^7.1.6":
- version "7.1.6"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.1.6.tgz#001303cf87a5b9d093494a4bf251d7b5d03d3999"
- integrity sha512-brwPBtVvdYdGxtenbQgfCdDPmtkmUBZPjUoK5SXJEBuHaA5BCubh9ly65fzXz7R6o5rA76Rs22ES8Z+HCc0YIQ==
+"@babel/generator@^7.2.2":
+ version "7.2.2"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.2.tgz#18c816c70962640eab42fe8cae5f3947a5c65ccc"
+ integrity sha512-I4o675J/iS8k+P38dvJ3IBGqObLXyQLTxtrR4u9cSUJOURvafeEWb/pFMOTwtNrmq73mJzyF6ueTbO1BtN0Zeg==
dependencies:
- "@babel/types" "^7.1.6"
+ "@babel/types" "^7.2.2"
jsesc "^2.5.1"
lodash "^4.17.10"
source-map "^0.5.0"
trim-right "^1.0.1"
-"@babel/generator@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.0.tgz#eaf3821fa0301d9d4aef88e63d4bcc19b73ba16c"
- integrity sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg==
+"@babel/generator@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e"
+ integrity sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==
dependencies:
- "@babel/types" "^7.2.0"
+ "@babel/types" "^7.3.4"
jsesc "^2.5.1"
- lodash "^4.17.10"
+ lodash "^4.17.11"
source-map "^0.5.0"
trim-right "^1.0.1"
@@ -234,6 +223,16 @@
"@babel/traverse" "^7.1.0"
"@babel/types" "^7.0.0"
+"@babel/helper-replace-supers@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz#a795208e9b911a6eeb08e5891faacf06e7013e13"
+ integrity sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A==
+ dependencies:
+ "@babel/helper-member-expression-to-functions" "^7.0.0"
+ "@babel/helper-optimise-call-expression" "^7.0.0"
+ "@babel/traverse" "^7.3.4"
+ "@babel/types" "^7.3.4"
+
"@babel/helper-simple-access@^7.1.0":
version "7.1.0"
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c"
@@ -259,15 +258,6 @@
"@babel/traverse" "^7.1.0"
"@babel/types" "^7.0.0"
-"@babel/helpers@^7.1.2":
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.1.2.tgz#ab752e8c35ef7d39987df4e8586c63b8846234b5"
- integrity sha512-Myc3pUE8eswD73aWcartxB16K6CGmHDv9KxOmD2CeOs/FaEAQodr3VYGmlvOmog60vNQ2w8QbatuahepZwrHiA==
- dependencies:
- "@babel/template" "^7.1.2"
- "@babel/traverse" "^7.1.0"
- "@babel/types" "^7.1.2"
-
"@babel/helpers@^7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.2.0.tgz#8335f3140f3144270dc63c4732a4f8b0a50b7a21"
@@ -301,15 +291,15 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.5.tgz#20b7d5e7e1811ba996f8a868962ea7dd2bfcd2fc"
integrity sha512-WXKf5K5HT6X0kKiCOezJZFljsfxKV1FpU8Tf1A7ZpGvyd/Q4hlrJm2EwoH2onaUq3O4tLDp+4gk0hHPsMyxmOg==
-"@babel/parser@^7.1.6":
- version "7.1.6"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.6.tgz#16e97aca1ec1062324a01c5a6a7d0df8dd189854"
- integrity sha512-dWP6LJm9nKT6ALaa+bnL247GHHMWir3vSlZ2+IHgHgktZQx0L3Uvq2uAWcuzIe+fujRsYWBW2q622C5UvGK9iQ==
+"@babel/parser@^7.2.2":
+ version "7.2.2"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.2.2.tgz#37ebdbc88a2e1ebc6c8dd3d35ea9436e3e39e477"
+ integrity sha512-UNTmQ5cSLDeBGBl+s7JeowkqIHgmFAGBnLDdIzFmUNSuS5JF0XBcN59jsh/vJO/YjfsBqMxhMjoFGmNExmf0FA==
-"@babel/parser@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.2.0.tgz#02d01dbc330b6cbf36b76ac93c50752c69027065"
- integrity sha512-M74+GvK4hn1eejD9lZ7967qAwvqTZayQa3g10ag4s9uewgR7TKjeaT0YMyoq+gVfKYABiWZ4MQD701/t5e1Jhg==
+"@babel/parser@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c"
+ integrity sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==
"@babel/plugin-proposal-async-generator-functions@^7.2.0":
version "7.2.0"
@@ -328,10 +318,10 @@
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-json-strings" "^7.2.0"
-"@babel/plugin-proposal-object-rest-spread@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.2.0.tgz#88f5fec3e7ad019014c97f7ee3c992f0adbf7fb8"
- integrity sha512-1L5mWLSvR76XYUQJXkd/EEQgjq8HHRP6lQuZTTg0VA4tTGPpGemmCdAfQIz1rzEuWAm+ecP8PyyEm30jC1eQCg==
+"@babel/plugin-proposal-object-rest-spread@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.4.tgz#47f73cf7f2a721aad5c0261205405c642e424654"
+ integrity sha512-j7VQmbbkA+qrzNqbKHrBsW3ddFnOeva6wzSe/zB7T+xaxGc+RCpwo44wCmRixAIGRoIpmVgvzFzNJqQcO3/9RA==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-object-rest-spread" "^7.2.0"
@@ -388,10 +378,10 @@
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-async-to-generator@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.2.0.tgz#68b8a438663e88519e65b776f8938f3445b1a2ff"
- integrity sha512-CEHzg4g5UraReozI9D4fblBYABs7IM6UerAVG7EJVrTLC5keh00aEuLUT+O40+mJCEzaXkYfTCUKIyeDfMOFFQ==
+"@babel/plugin-transform-async-to-generator@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.3.4.tgz#4e45408d3c3da231c0e7b823f407a53a7eb3048c"
+ integrity sha512-Y7nCzv2fw/jEZ9f678MuKdMo99MFDJMT/PvD9LisrR5JDFcJH6vYeH6RnjVt3p5tceyGRvTtEN0VOlU+rgHZjA==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
@@ -404,25 +394,25 @@
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-block-scoping@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.2.0.tgz#f17c49d91eedbcdf5dd50597d16f5f2f770132d4"
- integrity sha512-vDTgf19ZEV6mx35yiPJe4fS02mPQUUcBNwWQSZFXSzTSbsJFQvHt7DqyS3LK8oOWALFOsJ+8bbqBgkirZteD5Q==
+"@babel/plugin-transform-block-scoping@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.3.4.tgz#5c22c339de234076eee96c8783b2fed61202c5c4"
+ integrity sha512-blRr2O8IOZLAOJklXLV4WhcEzpYafYQKSGT3+R26lWG41u/FODJuBggehtOwilVAcFu393v3OFj+HmaE6tVjhA==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
- lodash "^4.17.10"
+ lodash "^4.17.11"
-"@babel/plugin-transform-classes@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.2.0.tgz#374f8876075d7d21fea55aeb5c53561259163f96"
- integrity sha512-aPCEkrhJYebDXcGTAP+cdUENkH7zqOlgbKwLbghjjHpJRJBWM/FSlCjMoPGA8oUdiMfOrk3+8EFPLLb5r7zj2w==
+"@babel/plugin-transform-classes@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.4.tgz#dc173cb999c6c5297e0b5f2277fdaaec3739d0cc"
+ integrity sha512-J9fAvCFBkXEvBimgYxCjvaVDzL6thk0j0dBvCeZmIUDBwyt+nv6HfbImsSrWsYXfDNDivyANgJlFXDUWRTZBuA==
dependencies:
"@babel/helper-annotate-as-pure" "^7.0.0"
"@babel/helper-define-map" "^7.1.0"
"@babel/helper-function-name" "^7.1.0"
"@babel/helper-optimise-call-expression" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-replace-supers" "^7.1.0"
+ "@babel/helper-replace-supers" "^7.3.4"
"@babel/helper-split-export-declaration" "^7.0.0"
globals "^11.1.0"
@@ -503,10 +493,10 @@
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/helper-simple-access" "^7.1.0"
-"@babel/plugin-transform-modules-systemjs@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.2.0.tgz#912bfe9e5ff982924c81d0937c92d24994bb9068"
- integrity sha512-aYJwpAhoK9a+1+O625WIjvMY11wkB/ok0WClVwmeo3mCjcNRjt+/8gHWrB5i+00mUju0gWsBkQnPpdvQ7PImmQ==
+"@babel/plugin-transform-modules-systemjs@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.3.4.tgz#813b34cd9acb6ba70a84939f3680be0eb2e58861"
+ integrity sha512-VZ4+jlGOF36S7TjKs8g4ojp4MEI+ebCQZdswWb/T9I4X84j8OtFAyjXjt/M16iIm5RIZn0UMQgg/VgIwo/87vw==
dependencies:
"@babel/helper-hoist-variables" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
@@ -519,6 +509,13 @@
"@babel/helper-module-transforms" "^7.1.0"
"@babel/helper-plugin-utils" "^7.0.0"
+"@babel/plugin-transform-named-capturing-groups-regex@^7.3.0":
+ version "7.3.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.3.0.tgz#140b52985b2d6ef0cb092ef3b29502b990f9cd50"
+ integrity sha512-NxIoNVhk9ZxS+9lSoAQ/LM0V2UEvARLttEHUrRDGKFaAxOYQcrkN/nLRE+BbbicCAvZPl7wMP0X60HsHE5DtQw==
+ dependencies:
+ regexp-tree "^0.1.0"
+
"@babel/plugin-transform-new-target@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz#ae8fbd89517fa7892d20e6564e641e8770c3aa4a"
@@ -543,12 +540,12 @@
"@babel/helper-get-function-arity" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-regenerator@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz#5b41686b4ed40bef874d7ed6a84bdd849c13e0c1"
- integrity sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw==
+"@babel/plugin-transform-regenerator@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.3.4.tgz#1601655c362f5b38eead6a52631f5106b29fa46a"
+ integrity sha512-hvJg8EReQvXT6G9H2MvNPXkv9zK36Vxa1+csAVTpE1J3j0zlHplw76uudEbJxgvqZzAq9Yh45FLD4pk5mKRFQA==
dependencies:
- regenerator-transform "^0.13.3"
+ regenerator-transform "^0.13.4"
"@babel/plugin-transform-shorthand-properties@^7.2.0":
version "7.2.0"
@@ -596,34 +593,35 @@
"@babel/helper-regex" "^7.0.0"
regexpu-core "^4.1.3"
-"@babel/polyfill@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.0.0.tgz#c8ff65c9ec3be6a1ba10113ebd40e8750fb90bff"
- integrity sha512-dnrMRkyyr74CRelJwvgnnSUDh2ge2NCTyHVwpOdvRMHtJUyxLtMAfhBN3s64pY41zdw0kgiLPh6S20eb1NcX6Q==
+"@babel/polyfill@^7.2.5":
+ version "7.2.5"
+ resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.2.5.tgz#6c54b964f71ad27edddc567d065e57e87ed7fa7d"
+ integrity sha512-8Y/t3MWThtMLYr0YNC/Q76tqN1w30+b0uQMeFUYauG2UGTR19zyUtFrAzT23zNtBxPp+LbE5E/nwV/q/r3y6ug==
dependencies:
core-js "^2.5.7"
- regenerator-runtime "^0.11.1"
+ regenerator-runtime "^0.12.0"
-"@babel/preset-env@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.2.0.tgz#a5030e7e4306af5a295dd5d7c78dc5464af3fee2"
- integrity sha512-haGR38j5vOGVeBatrQPr3l0xHbs14505DcM57cbJy48kgMFvvHHoYEhHuRV+7vi559yyAUAVbTWzbK/B/pzJng==
+"@babel/preset-env@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.4.tgz#887cf38b6d23c82f19b5135298bdb160062e33e1"
+ integrity sha512-2mwqfYMK8weA0g0uBKOt4FE3iEodiHy9/CW0b+nWXcbL+pGzLx8ESYc+j9IIxr6LTDHWKgPm71i9smo02bw+gA==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-proposal-async-generator-functions" "^7.2.0"
"@babel/plugin-proposal-json-strings" "^7.2.0"
- "@babel/plugin-proposal-object-rest-spread" "^7.2.0"
+ "@babel/plugin-proposal-object-rest-spread" "^7.3.4"
"@babel/plugin-proposal-optional-catch-binding" "^7.2.0"
"@babel/plugin-proposal-unicode-property-regex" "^7.2.0"
"@babel/plugin-syntax-async-generators" "^7.2.0"
+ "@babel/plugin-syntax-json-strings" "^7.2.0"
"@babel/plugin-syntax-object-rest-spread" "^7.2.0"
"@babel/plugin-syntax-optional-catch-binding" "^7.2.0"
"@babel/plugin-transform-arrow-functions" "^7.2.0"
- "@babel/plugin-transform-async-to-generator" "^7.2.0"
+ "@babel/plugin-transform-async-to-generator" "^7.3.4"
"@babel/plugin-transform-block-scoped-functions" "^7.2.0"
- "@babel/plugin-transform-block-scoping" "^7.2.0"
- "@babel/plugin-transform-classes" "^7.2.0"
+ "@babel/plugin-transform-block-scoping" "^7.3.4"
+ "@babel/plugin-transform-classes" "^7.3.4"
"@babel/plugin-transform-computed-properties" "^7.2.0"
"@babel/plugin-transform-destructuring" "^7.2.0"
"@babel/plugin-transform-dotall-regex" "^7.2.0"
@@ -634,12 +632,13 @@
"@babel/plugin-transform-literals" "^7.2.0"
"@babel/plugin-transform-modules-amd" "^7.2.0"
"@babel/plugin-transform-modules-commonjs" "^7.2.0"
- "@babel/plugin-transform-modules-systemjs" "^7.2.0"
+ "@babel/plugin-transform-modules-systemjs" "^7.3.4"
"@babel/plugin-transform-modules-umd" "^7.2.0"
+ "@babel/plugin-transform-named-capturing-groups-regex" "^7.3.0"
"@babel/plugin-transform-new-target" "^7.0.0"
"@babel/plugin-transform-object-super" "^7.2.0"
"@babel/plugin-transform-parameters" "^7.2.0"
- "@babel/plugin-transform-regenerator" "^7.0.0"
+ "@babel/plugin-transform-regenerator" "^7.3.4"
"@babel/plugin-transform-shorthand-properties" "^7.2.0"
"@babel/plugin-transform-spread" "^7.2.0"
"@babel/plugin-transform-sticky-regex" "^7.2.0"
@@ -669,6 +668,15 @@
"@babel/parser" "^7.1.2"
"@babel/types" "^7.1.2"
+"@babel/template@^7.2.2":
+ version "7.2.2"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907"
+ integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ "@babel/parser" "^7.2.2"
+ "@babel/types" "^7.2.2"
+
"@babel/traverse@^7.1.0":
version "7.1.0"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.0.tgz#503ec6669387efd182c3888c4eec07bcc45d91b2"
@@ -699,21 +707,36 @@
globals "^11.1.0"
lodash "^4.17.10"
-"@babel/traverse@^7.1.6":
- version "7.1.6"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.6.tgz#c8db9963ab4ce5b894222435482bd8ea854b7b5c"
- integrity sha512-CXedit6GpISz3sC2k2FsGCUpOhUqKdyL0lqNrImQojagnUMXf8hex4AxYFRuMkNGcvJX5QAFGzB5WJQmSv8SiQ==
+"@babel/traverse@^7.2.2":
+ version "7.2.2"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.2.tgz#961039de1f9bcb946d807efe2dba9c92e859d188"
+ integrity sha512-E5Bn9FSwHpSkUhthw/XEuvFZxIgrqb9M8cX8j5EUQtrUG5DQUy6bFyl7G7iQ1D1Czudor+xkmp81JbLVVM0Sjg==
dependencies:
"@babel/code-frame" "^7.0.0"
- "@babel/generator" "^7.1.6"
+ "@babel/generator" "^7.2.2"
"@babel/helper-function-name" "^7.1.0"
"@babel/helper-split-export-declaration" "^7.0.0"
- "@babel/parser" "^7.1.6"
- "@babel/types" "^7.1.6"
+ "@babel/parser" "^7.2.2"
+ "@babel/types" "^7.2.2"
debug "^4.1.0"
globals "^11.1.0"
lodash "^4.17.10"
+"@babel/traverse@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.3.4.tgz#1330aab72234f8dea091b08c4f8b9d05c7119e06"
+ integrity sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ "@babel/generator" "^7.3.4"
+ "@babel/helper-function-name" "^7.1.0"
+ "@babel/helper-split-export-declaration" "^7.0.0"
+ "@babel/parser" "^7.3.4"
+ "@babel/types" "^7.3.4"
+ debug "^4.1.0"
+ globals "^11.1.0"
+ lodash "^4.17.11"
+
"@babel/types@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0.tgz#6e191793d3c854d19c6749989e3bc55f0e962118"
@@ -741,24 +764,33 @@
lodash "^4.17.10"
to-fast-properties "^2.0.0"
-"@babel/types@^7.1.6":
- version "7.1.6"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.1.6.tgz#0adb330c3a281348a190263aceb540e10f04bcce"
- integrity sha512-DMiUzlY9DSjVsOylJssxLHSgj6tWM9PRFJOGW/RaOglVOK9nzTxoOMfTfRQXGUCUQ/HmlG2efwC+XqUEJ5ay4w==
+"@babel/types@^7.2.0":
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.0.tgz#7941c5b2d8060e06f9601d6be7c223eef906d5d8"
+ integrity sha512-b4v7dyfApuKDvmPb+O488UlGuR1WbwMXFsO/cyqMrnfvRAChZKJAYeeglWTjUO1b9UghKKgepAQM5tsvBJca6A==
dependencies:
esutils "^2.0.2"
lodash "^4.17.10"
to-fast-properties "^2.0.0"
-"@babel/types@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.0.tgz#7941c5b2d8060e06f9601d6be7c223eef906d5d8"
- integrity sha512-b4v7dyfApuKDvmPb+O488UlGuR1WbwMXFsO/cyqMrnfvRAChZKJAYeeglWTjUO1b9UghKKgepAQM5tsvBJca6A==
+"@babel/types@^7.2.2":
+ version "7.2.2"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.2.tgz#44e10fc24e33af524488b716cdaee5360ea8ed1e"
+ integrity sha512-fKCuD6UFUMkR541eDWL+2ih/xFZBXPOg/7EQFeTluMDebfqR4jrpaCjLhkWlQS4hT6nRa2PMEgXKbRB5/H2fpg==
dependencies:
esutils "^2.0.2"
lodash "^4.17.10"
to-fast-properties "^2.0.0"
+"@babel/types@^7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.4.tgz#bf482eaeaffb367a28abbf9357a94963235d90ed"
+ integrity sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==
+ dependencies:
+ esutils "^2.0.2"
+ lodash "^4.17.11"
+ to-fast-properties "^2.0.0"
+
"@csstools/convert-colors@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
@@ -772,187 +804,218 @@
call-me-maybe "^1.0.1"
glob-to-regexp "^0.3.0"
-"@nodelib/fs.stat@^1.0.1":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.2.tgz#54c5a964462be3d4d78af631363c18d6fa91ac26"
- integrity sha512-yprFYuno9FtNsSHVlSWd+nRlmGoAbqbeCwOryP6sC/zoCjhpArcRMYp19EvpSUSizJAlsXEwJv+wcWS9XaXdMw==
-
-"@webassemblyjs/ast@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz#b988582cafbb2b095e8b556526f30c90d057cace"
- integrity sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA==
- dependencies:
- "@webassemblyjs/helper-module-context" "1.7.11"
- "@webassemblyjs/helper-wasm-bytecode" "1.7.11"
- "@webassemblyjs/wast-parser" "1.7.11"
-
-"@webassemblyjs/floating-point-hex-parser@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz#a69f0af6502eb9a3c045555b1a6129d3d3f2e313"
- integrity sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg==
-
-"@webassemblyjs/helper-api-error@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz#c7b6bb8105f84039511a2b39ce494f193818a32a"
- integrity sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg==
-
-"@webassemblyjs/helper-buffer@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz#3122d48dcc6c9456ed982debe16c8f37101df39b"
- integrity sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w==
-
-"@webassemblyjs/helper-code-frame@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz#cf8f106e746662a0da29bdef635fcd3d1248364b"
- integrity sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw==
- dependencies:
- "@webassemblyjs/wast-printer" "1.7.11"
-
-"@webassemblyjs/helper-fsm@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz#df38882a624080d03f7503f93e3f17ac5ac01181"
- integrity sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A==
-
-"@webassemblyjs/helper-module-context@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz#d874d722e51e62ac202476935d649c802fa0e209"
- integrity sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg==
-
-"@webassemblyjs/helper-wasm-bytecode@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz#dd9a1e817f1c2eb105b4cf1013093cb9f3c9cb06"
- integrity sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ==
-
-"@webassemblyjs/helper-wasm-section@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz#9c9ac41ecf9fbcfffc96f6d2675e2de33811e68a"
- integrity sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q==
- dependencies:
- "@webassemblyjs/ast" "1.7.11"
- "@webassemblyjs/helper-buffer" "1.7.11"
- "@webassemblyjs/helper-wasm-bytecode" "1.7.11"
- "@webassemblyjs/wasm-gen" "1.7.11"
-
-"@webassemblyjs/ieee754@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz#c95839eb63757a31880aaec7b6512d4191ac640b"
- integrity sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ==
+"@nodelib/fs.stat@^1.1.2":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
+ integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
+
+"@types/node@*":
+ version "10.12.18"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
+ integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
+
+"@types/unist@*", "@types/unist@^2.0.0":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.2.tgz#5dc0a7f76809b7518c0df58689cd16a19bd751c6"
+ integrity sha512-iHI60IbyfQilNubmxsq4zqSjdynlmc2Q/QvH9kjzg9+CCYVVzq1O6tc7VBzSygIwnmOt07w80IG6HDQvjv3Liw==
+
+"@types/vfile-message@*":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@types/vfile-message/-/vfile-message-1.0.1.tgz#e1e9895cc6b36c462d4244e64e6d0b6eaf65355a"
+ integrity sha512-mlGER3Aqmq7bqR1tTTIVHq8KSAFFRyGbrxuM8C/H82g6k7r2fS+IMEkIu3D7JHzG10NvPdR8DNx0jr0pwpp4dA==
+ dependencies:
+ "@types/node" "*"
+ "@types/unist" "*"
+
+"@types/vfile@^3.0.0":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/vfile/-/vfile-3.0.2.tgz#19c18cd232df11ce6fa6ad80259bc86c366b09b9"
+ integrity sha512-b3nLFGaGkJ9rzOcuXRfHkZMdjsawuDD0ENL9fzTophtBg8FJHSGbH7daXkEpcwy3v7Xol3pAvsmlYyFhR4pqJw==
+ dependencies:
+ "@types/node" "*"
+ "@types/unist" "*"
+ "@types/vfile-message" "*"
+
+"@webassemblyjs/ast@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359"
+ integrity sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==
+ dependencies:
+ "@webassemblyjs/helper-module-context" "1.8.5"
+ "@webassemblyjs/helper-wasm-bytecode" "1.8.5"
+ "@webassemblyjs/wast-parser" "1.8.5"
+
+"@webassemblyjs/floating-point-hex-parser@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721"
+ integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==
+
+"@webassemblyjs/helper-api-error@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7"
+ integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==
+
+"@webassemblyjs/helper-buffer@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204"
+ integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==
+
+"@webassemblyjs/helper-code-frame@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e"
+ integrity sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==
+ dependencies:
+ "@webassemblyjs/wast-printer" "1.8.5"
+
+"@webassemblyjs/helper-fsm@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452"
+ integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==
+
+"@webassemblyjs/helper-module-context@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245"
+ integrity sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==
+ dependencies:
+ "@webassemblyjs/ast" "1.8.5"
+ mamacro "^0.0.3"
+
+"@webassemblyjs/helper-wasm-bytecode@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61"
+ integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==
+
+"@webassemblyjs/helper-wasm-section@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf"
+ integrity sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==
+ dependencies:
+ "@webassemblyjs/ast" "1.8.5"
+ "@webassemblyjs/helper-buffer" "1.8.5"
+ "@webassemblyjs/helper-wasm-bytecode" "1.8.5"
+ "@webassemblyjs/wasm-gen" "1.8.5"
+
+"@webassemblyjs/ieee754@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e"
+ integrity sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==
dependencies:
"@xtuc/ieee754" "^1.2.0"
-"@webassemblyjs/leb128@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.11.tgz#d7267a1ee9c4594fd3f7e37298818ec65687db63"
- integrity sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw==
- dependencies:
- "@xtuc/long" "4.2.1"
-
-"@webassemblyjs/utf8@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.11.tgz#06d7218ea9fdc94a6793aa92208160db3d26ee82"
- integrity sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA==
-
-"@webassemblyjs/wasm-edit@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz#8c74ca474d4f951d01dbae9bd70814ee22a82005"
- integrity sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg==
- dependencies:
- "@webassemblyjs/ast" "1.7.11"
- "@webassemblyjs/helper-buffer" "1.7.11"
- "@webassemblyjs/helper-wasm-bytecode" "1.7.11"
- "@webassemblyjs/helper-wasm-section" "1.7.11"
- "@webassemblyjs/wasm-gen" "1.7.11"
- "@webassemblyjs/wasm-opt" "1.7.11"
- "@webassemblyjs/wasm-parser" "1.7.11"
- "@webassemblyjs/wast-printer" "1.7.11"
-
-"@webassemblyjs/wasm-gen@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz#9bbba942f22375686a6fb759afcd7ac9c45da1a8"
- integrity sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA==
- dependencies:
- "@webassemblyjs/ast" "1.7.11"
- "@webassemblyjs/helper-wasm-bytecode" "1.7.11"
- "@webassemblyjs/ieee754" "1.7.11"
- "@webassemblyjs/leb128" "1.7.11"
- "@webassemblyjs/utf8" "1.7.11"
-
-"@webassemblyjs/wasm-opt@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz#b331e8e7cef8f8e2f007d42c3a36a0580a7d6ca7"
- integrity sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg==
- dependencies:
- "@webassemblyjs/ast" "1.7.11"
- "@webassemblyjs/helper-buffer" "1.7.11"
- "@webassemblyjs/wasm-gen" "1.7.11"
- "@webassemblyjs/wasm-parser" "1.7.11"
-
-"@webassemblyjs/wasm-parser@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz#6e3d20fa6a3519f6b084ef9391ad58211efb0a1a"
- integrity sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg==
- dependencies:
- "@webassemblyjs/ast" "1.7.11"
- "@webassemblyjs/helper-api-error" "1.7.11"
- "@webassemblyjs/helper-wasm-bytecode" "1.7.11"
- "@webassemblyjs/ieee754" "1.7.11"
- "@webassemblyjs/leb128" "1.7.11"
- "@webassemblyjs/utf8" "1.7.11"
-
-"@webassemblyjs/wast-parser@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz#25bd117562ca8c002720ff8116ef9072d9ca869c"
- integrity sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ==
- dependencies:
- "@webassemblyjs/ast" "1.7.11"
- "@webassemblyjs/floating-point-hex-parser" "1.7.11"
- "@webassemblyjs/helper-api-error" "1.7.11"
- "@webassemblyjs/helper-code-frame" "1.7.11"
- "@webassemblyjs/helper-fsm" "1.7.11"
- "@xtuc/long" "4.2.1"
-
-"@webassemblyjs/wast-printer@1.7.11":
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz#c4245b6de242cb50a2cc950174fdbf65c78d7813"
- integrity sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg==
- dependencies:
- "@webassemblyjs/ast" "1.7.11"
- "@webassemblyjs/wast-parser" "1.7.11"
- "@xtuc/long" "4.2.1"
+"@webassemblyjs/leb128@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10"
+ integrity sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==
+ dependencies:
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/utf8@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc"
+ integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==
+
+"@webassemblyjs/wasm-edit@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a"
+ integrity sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==
+ dependencies:
+ "@webassemblyjs/ast" "1.8.5"
+ "@webassemblyjs/helper-buffer" "1.8.5"
+ "@webassemblyjs/helper-wasm-bytecode" "1.8.5"
+ "@webassemblyjs/helper-wasm-section" "1.8.5"
+ "@webassemblyjs/wasm-gen" "1.8.5"
+ "@webassemblyjs/wasm-opt" "1.8.5"
+ "@webassemblyjs/wasm-parser" "1.8.5"
+ "@webassemblyjs/wast-printer" "1.8.5"
+
+"@webassemblyjs/wasm-gen@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc"
+ integrity sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==
+ dependencies:
+ "@webassemblyjs/ast" "1.8.5"
+ "@webassemblyjs/helper-wasm-bytecode" "1.8.5"
+ "@webassemblyjs/ieee754" "1.8.5"
+ "@webassemblyjs/leb128" "1.8.5"
+ "@webassemblyjs/utf8" "1.8.5"
+
+"@webassemblyjs/wasm-opt@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264"
+ integrity sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==
+ dependencies:
+ "@webassemblyjs/ast" "1.8.5"
+ "@webassemblyjs/helper-buffer" "1.8.5"
+ "@webassemblyjs/wasm-gen" "1.8.5"
+ "@webassemblyjs/wasm-parser" "1.8.5"
+
+"@webassemblyjs/wasm-parser@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d"
+ integrity sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==
+ dependencies:
+ "@webassemblyjs/ast" "1.8.5"
+ "@webassemblyjs/helper-api-error" "1.8.5"
+ "@webassemblyjs/helper-wasm-bytecode" "1.8.5"
+ "@webassemblyjs/ieee754" "1.8.5"
+ "@webassemblyjs/leb128" "1.8.5"
+ "@webassemblyjs/utf8" "1.8.5"
+
+"@webassemblyjs/wast-parser@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c"
+ integrity sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==
+ dependencies:
+ "@webassemblyjs/ast" "1.8.5"
+ "@webassemblyjs/floating-point-hex-parser" "1.8.5"
+ "@webassemblyjs/helper-api-error" "1.8.5"
+ "@webassemblyjs/helper-code-frame" "1.8.5"
+ "@webassemblyjs/helper-fsm" "1.8.5"
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/wast-printer@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc"
+ integrity sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==
+ dependencies:
+ "@webassemblyjs/ast" "1.8.5"
+ "@webassemblyjs/wast-parser" "1.8.5"
+ "@xtuc/long" "4.2.2"
"@xtuc/ieee754@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
-"@xtuc/long@4.2.1":
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8"
- integrity sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==
+"@xtuc/long@4.2.2":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
+ integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
abbrev@1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
-acorn-dynamic-import@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278"
- integrity sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==
- dependencies:
- acorn "^5.0.0"
+acorn-dynamic-import@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948"
+ integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==
-acorn-jsx@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e"
- integrity sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw==
- dependencies:
- acorn "^5.0.3"
+acorn-jsx@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e"
+ integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==
+
+acorn@^6.0.5:
+ version "6.0.5"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.5.tgz#81730c0815f3f3b34d8efa95cb7430965f4d887a"
+ integrity sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg==
-acorn@^5.0.0, acorn@^5.0.3, acorn@^5.6.0, acorn@^5.6.2:
- version "5.7.2"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.2.tgz#91fa871883485d06708800318404e72bfb26dcc5"
- integrity sha512-cJrKCNcr2kv8dlDnbw+JPUGjHZzo4myaxOLmpOX8a+rgX94YeTcTMv/LFJUSByRpc+i4GgVnnhLxvMu/2Y+rqw==
+acorn@^6.0.7:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.0.tgz#b0a3be31752c97a0f7013c5f4903b71a05db6818"
+ integrity sha512-MW/FjM+IvU9CgBzjO3UIPCE2pyEwUsoFl+VGdczOPEdxfGFjuKny/gN54mOuX7Qxmb9Rg9MCn2oKiSUeW+pjrw==
ajv-errors@^1.0.0:
version "1.0.0"
@@ -974,15 +1037,25 @@ ajv@^6.1.0, ajv@^6.5.3:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
+ajv@^6.9.1:
+ version "6.9.1"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.9.1.tgz#a4d3683d74abc5670e75f0b16520f70a20ea8dc1"
+ integrity sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==
+ dependencies:
+ fast-deep-equal "^2.0.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
alphanum-sort@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
-ansi-escapes@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30"
- integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==
+ansi-escapes@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
+ integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
ansi-regex@^2.0.0:
version "2.1.1"
@@ -994,12 +1067,12 @@ ansi-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
-ansi-styles@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
- integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+ansi-regex@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9"
+ integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==
-ansi-styles@^3.2.1:
+ansi-styles@^3.2.0, ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
@@ -1054,7 +1127,7 @@ array-find-index@^1.0.1:
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
-array-union@^1.0.1:
+array-union@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=
@@ -1071,7 +1144,7 @@ array-unique@^0.3.2:
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
-arrify@^1.0.0, arrify@^1.0.1:
+arrify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
@@ -1097,6 +1170,11 @@ assign-symbols@^1.0.0:
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
+astral-regex@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
+ integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
+
async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
@@ -1119,33 +1197,24 @@ autoprefixer@^9.0.0:
postcss "^7.0.2"
postcss-value-parser "^3.2.3"
-autoprefixer@^9.3.1:
- version "9.3.1"
- resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.3.1.tgz#71b622174de2b783d5fd99f9ad617b7a3c78443e"
- integrity sha512-DY9gOh8z3tnCbJ13JIWaeQsoYncTGdsrgCceBaQSIL4nvdrLxgbRSBPevg2XbX7u4QCSfLheSJEEIUUSlkbx6Q==
+autoprefixer@^9.4.9:
+ version "9.4.9"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.9.tgz#0d3eb86bc1d1228551abcf55220d6fd246b6cb31"
+ integrity sha512-OyUl7KvbGBoFQbGQu51hMywz1aaVeud/6uX8r1R1DNcqFvqGUUy6+BDHnAZE8s5t5JyEObaSw+O1DpAdjAmLuw==
dependencies:
- browserslist "^4.3.3"
- caniuse-lite "^1.0.30000898"
+ browserslist "^4.4.2"
+ caniuse-lite "^1.0.30000939"
normalize-range "^0.1.2"
num2fraction "^1.2.2"
- postcss "^7.0.5"
+ postcss "^7.0.14"
postcss-value-parser "^3.3.1"
-babel-code-frame@^6.26.0:
- version "6.26.0"
- resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
- integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
- dependencies:
- chalk "^1.1.3"
- esutils "^2.0.2"
- js-tokens "^3.0.2"
-
-babel-loader@^8.0.4:
- version "8.0.4"
- resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.4.tgz#7bbf20cbe4560629e2e41534147692d3fecbdce6"
- integrity sha512-fhBhNkUToJcW9nV46v8w87AJOwAJDz84c1CL57n3Stj73FANM/b9TbCUK4YhdOwEyZ+OxhYpdeZDNzSI29Firw==
+babel-loader@^8.0.5:
+ version "8.0.5"
+ resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.5.tgz#225322d7509c2157655840bba52e46b6c2f2fe33"
+ integrity sha512-NTnHnVRd2JnRqPC0vW+iOQWU5pchDbYXsG2E6DMXEpMfUcQKclF9gmf3G3ZMhzG7IG9ji4coL0cm+FxeWxDpnw==
dependencies:
- find-cache-dir "^1.0.0"
+ find-cache-dir "^2.0.0"
loader-utils "^1.0.2"
mkdirp "^0.5.1"
util.promisify "^1.0.0"
@@ -1183,6 +1252,11 @@ big.js@^3.1.3:
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==
+big.js@^5.2.2:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
+ integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
+
binary-extensions@^1.0.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
@@ -1300,7 +1374,7 @@ browserslist@^4.0.0, browserslist@^4.1.0:
electron-to-chromium "^1.3.62"
node-releases "^1.0.0-alpha.11"
-browserslist@^4.3.3, browserslist@^4.3.4:
+browserslist@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.3.4.tgz#4477b737db6a1b07077275b24791e680d4300425"
integrity sha512-u5iz+ijIMUlmV8blX82VGFrB9ecnUg5qEt55CMZ/YJEhha+d8qpBfOFuutJ6F/VKRXjZoD33b6uvarpPxcl3RA==
@@ -1309,6 +1383,15 @@ browserslist@^4.3.3, browserslist@^4.3.4:
electron-to-chromium "^1.3.82"
node-releases "^1.0.1"
+browserslist@^4.4.2:
+ version "4.4.2"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.2.tgz#6ea8a74d6464bb0bd549105f659b41197d8f0ba2"
+ integrity sha512-ISS/AIAiHERJ3d45Fz0AVYKkgcy+F/eJHzKEvv1j0wwKGKD9T3BrwKr/5g45L+Y4XIK5PlTqefHciRFcfE1Jxg==
+ dependencies:
+ caniuse-lite "^1.0.30000939"
+ electron-to-chromium "^1.3.113"
+ node-releases "^1.1.8"
+
buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
@@ -1378,17 +1461,10 @@ call-me-maybe@^1.0.1:
resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
-caller-path@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
- integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=
- dependencies:
- callsites "^0.2.0"
-
-callsites@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
- integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=
+callsites@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3"
+ integrity sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==
camelcase-keys@^4.0.0:
version "4.2.0"
@@ -1404,6 +1480,16 @@ camelcase@^4.1.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
+camelcase@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42"
+ integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==
+
+camelcase@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.2.0.tgz#e7522abda5ed94cc0489e1b8466610e88404cf45"
+ integrity sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==
+
caniuse-api@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
@@ -1424,27 +1510,21 @@ caniuse-lite@^1.0.30000884:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000885.tgz#e889e9f8e7e50e769f2a49634c932b8aee622984"
integrity sha512-cXKbYwpxBLd7qHyej16JazPoUacqoVuDhvR61U7Fr5vSxMUiodzcYa1rQYRYfZ5GexV03vGZHd722vNPLjPJGQ==
-caniuse-lite@^1.0.30000898, caniuse-lite@^1.0.30000899, caniuse-lite@^1.0.30000905:
+caniuse-lite@^1.0.30000899:
version "1.0.30000907"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000907.tgz#0b9899bde53fb1c30e214fb12402361e02ff5c42"
integrity sha512-No5sQ/OB2Nmka8MNOOM6nJx+Hxt6MQ6h7t7kgJFu9oTuwjykyKRSBP/+i/QAyFHxeHB+ddE0Da1CG5ihx9oehQ==
+caniuse-lite@^1.0.30000939:
+ version "1.0.30000939"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000939.tgz#b9ab7ac9e861bf78840b80c5dfbc471a5cd7e679"
+ integrity sha512-oXB23ImDJOgQpGjRv1tCtzAvJr4/OvrHi5SO2vUgB0g0xpdZZoA/BxfImiWfdwoYdUTtQrPsXsvYU/dmCSM8gg==
+
ccount@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.3.tgz#f1cec43f332e2ea5a569fd46f9f5bde4e6102aff"
integrity sha512-Jt9tIBkRc9POUof7QA/VwWd+58fKkEEfI+/t1/eOlxKM7ZhrczNzMFefge7Ai+39y1pR/pP6cI19guHy3FSLmw==
-chalk@^1.1.3:
- version "1.1.3"
- resolved "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
- integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
- dependencies:
- ansi-styles "^2.2.1"
- escape-string-regexp "^1.0.2"
- has-ansi "^2.0.0"
- strip-ansi "^3.0.0"
- supports-color "^2.0.0"
-
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
@@ -1454,6 +1534,15 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
+chalk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
character-entities-html4@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.2.tgz#c44fdde3ce66b52e8d321d6c1bf46101f0150610"
@@ -1519,11 +1608,6 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
inherits "^2.0.1"
safe-buffer "^5.0.1"
-circular-json@^0.3.1:
- version "0.3.3"
- resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
- integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==
-
class-utils@^0.3.5:
version "0.3.6"
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
@@ -1546,6 +1630,16 @@ cli-cursor@^2.1.0:
dependencies:
restore-cursor "^2.0.0"
+cli-table3@^0.5.0:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202"
+ integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==
+ dependencies:
+ object-assign "^4.1.0"
+ string-width "^2.1.1"
+ optionalDependencies:
+ colors "^1.1.2"
+
cli-width@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
@@ -1626,6 +1720,11 @@ color@^3.0.0:
color-convert "^1.9.1"
color-string "^1.5.2"
+colors@^1.1.2:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d"
+ integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==
+
colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
@@ -1762,6 +1861,15 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
+cross-spawn@^5.0.1:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
+ integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
+ dependencies:
+ lru-cache "^4.0.1"
+ shebang-command "^1.2.0"
+ which "^1.2.9"
+
cross-spawn@^6.0.0, cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
@@ -1790,6 +1898,13 @@ crypto-browserify@^3.11.0:
randombytes "^2.0.0"
randomfill "^1.0.3"
+css-blank-pseudo@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5"
+ integrity sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==
+ dependencies:
+ postcss "^7.0.5"
+
css-color-names@0.0.4, css-color-names@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
@@ -1803,25 +1918,32 @@ css-declaration-sorter@^3.0.0:
postcss "^6.0.0"
timsort "^0.3.0"
-css-loader@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-1.0.1.tgz#6885bb5233b35ec47b006057da01cc640b6b79fe"
- integrity sha512-+ZHAZm/yqvJ2kDtPne3uX0C+Vr3Zn5jFn2N4HywtS5ujwvsVkyg0VArEXpl3BgczDA8anieki1FIzhchX4yrDw==
+css-has-pseudo@^0.10.0:
+ version "0.10.0"
+ resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz#3c642ab34ca242c59c41a125df9105841f6966ee"
+ integrity sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==
dependencies:
- babel-code-frame "^6.26.0"
- css-selector-tokenizer "^0.7.0"
- icss-utils "^2.1.0"
- loader-utils "^1.0.2"
- lodash "^4.17.11"
- postcss "^6.0.23"
- postcss-modules-extract-imports "^1.2.0"
- postcss-modules-local-by-default "^1.2.0"
- postcss-modules-scope "^1.1.0"
- postcss-modules-values "^1.3.0"
+ postcss "^7.0.6"
+ postcss-selector-parser "^5.0.0-rc.4"
+
+css-loader@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.1.tgz#d8254f72e412bb2238bb44dd674ffbef497333ea"
+ integrity sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w==
+ dependencies:
+ camelcase "^5.2.0"
+ icss-utils "^4.1.0"
+ loader-utils "^1.2.3"
+ normalize-path "^3.0.0"
+ postcss "^7.0.14"
+ postcss-modules-extract-imports "^2.0.0"
+ postcss-modules-local-by-default "^2.0.6"
+ postcss-modules-scope "^2.1.0"
+ postcss-modules-values "^2.0.0"
postcss-value-parser "^3.3.0"
- source-list-map "^2.0.0"
+ schema-utils "^1.0.0"
-css-prefers-color-scheme@^3.0.0:
+css-prefers-color-scheme@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz#6f830a2714199d4f0d0d0bb8a27916ed65cff1f4"
integrity sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg==
@@ -1843,15 +1965,6 @@ css-select@^2.0.0:
domutils "^1.7.0"
nth-check "^1.0.1"
-css-selector-tokenizer@^0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86"
- integrity sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=
- dependencies:
- cssesc "^0.1.0"
- fastparse "^1.1.1"
- regexpu-core "^1.0.0"
-
css-tree@1.0.0-alpha.28:
version "1.0.0-alpha.28"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.28.tgz#8e8968190d886c9477bc8d61e96f61af3f7ffa7f"
@@ -1883,21 +1996,21 @@ css-what@2.1:
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd"
integrity sha1-lGfQMsOM+u+58teVASUwYvh/ob0=
-cssdb@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.2.0.tgz#89623ec696121d0688080ccdcd4627c7e6c6ee0d"
- integrity sha512-27CuM+rp1/HIH4hkiOvrRUjgv31WamWk7+XSGz7OP/uWR8EOMeXOh4Ncpa/Eq1eO/1eRhQx7HWj8KEbt4nKQBA==
-
-cssesc@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
- integrity sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=
+cssdb@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.3.0.tgz#2e1229900616f80c66ff2d568ea2b4f92db1c78c"
+ integrity sha512-VHPES/+c9s+I0ryNj+PXvp84nz+ms843z/efpaEINwP/QfGsINL3gpLp5qjapzDNzNzbXxur8uxKxSXImrg4ag==
cssesc@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703"
integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==
+cssesc@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+ integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
cssnano-preset-default@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.0.tgz#c334287b4f7d49fb2d170a92f9214655788e3b6b"
@@ -2026,18 +2139,11 @@ decamelize-keys@^1.0.0:
decamelize "^1.1.0"
map-obj "^1.0.0"
-decamelize@^1.1.0:
+decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
-decamelize@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7"
- integrity sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==
- dependencies:
- xregexp "4.0.0"
-
decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
@@ -2082,19 +2188,6 @@ define-property@^2.0.2:
is-descriptor "^1.0.2"
isobject "^3.0.1"
-del@^2.0.2:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8"
- integrity sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=
- dependencies:
- globby "^5.0.0"
- is-path-cwd "^1.0.0"
- is-path-in-cwd "^1.0.0"
- object-assign "^4.0.1"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
- rimraf "^2.2.8"
-
delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
@@ -2108,6 +2201,11 @@ des.js@^1.0.0:
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
+detect-file@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
+ integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
+
detect-libc@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
@@ -2122,18 +2220,17 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
-dir-glob@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034"
- integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==
+dir-glob@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.1.tgz#ce8413234ffe8452b76b7741c32f116cf2a7b1a7"
+ integrity sha512-UN6X6XwRjllabfRhBdkVSo63uurJ8nSvMGrwl94EYVz6g+exhTV+yVSYk5VC/xl3MBFBTtC0J20uFKce4Brrng==
dependencies:
- arrify "^1.0.1"
path-type "^3.0.0"
-doctrine@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
- integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
+doctrine@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+ integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
dependencies:
esutils "^2.0.2"
@@ -2192,6 +2289,11 @@ duplexify@^3.4.2, duplexify@^3.6.0:
readable-stream "^2.0.0"
stream-shift "^1.0.0"
+electron-to-chromium@^1.3.113:
+ version "1.3.113"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz#b1ccf619df7295aea17bc6951dc689632629e4a9"
+ integrity sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g==
+
electron-to-chromium@^1.3.62:
version "1.3.63"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.63.tgz#6485f5f4f3375358aa8fa23c2029ada208483b8d"
@@ -2202,10 +2304,10 @@ electron-to-chromium@^1.3.82:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.84.tgz#2e55df59e818f150a9f61b53471ebf4f0feecc65"
integrity sha512-IYhbzJYOopiTaNWMBp7RjbecUBsbnbDneOP86f3qvS0G0xfzwNSvMJpTrvi5/Y1gU7tg2NAgeg8a8rCYvW9Whw==
-element-closest@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/element-closest/-/element-closest-2.0.2.tgz#72a740a107453382e28df9ce5dbb5a8df0f966ec"
- integrity sha1-cqdAoQdFM4LijfnOXbtajfD5Zuw=
+element-closest@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/element-closest/-/element-closest-3.0.1.tgz#0b2000266ae43a800274401dc39486f5e4bfbce2"
+ integrity sha512-Wm8B0in+k6GsSCra8vLVnFIjIrff2T1s2b++jU6VL6mqIteP19THxDXwT5JDrmJPlqT3YifOK9cu28+uRGUdew==
elliptic@^6.0.0:
version "6.4.1"
@@ -2220,6 +2322,11 @@ elliptic@^6.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.0"
+emoji-regex@^7.0.1:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
+ integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
+
emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
@@ -2280,15 +2387,15 @@ es-to-primitive@^1.1.1:
is-date-object "^1.0.1"
is-symbol "^1.0.1"
-escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
-eslint-loader@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.1.1.tgz#2a9251523652430bfdd643efdb0afc1a2a89546a"
- integrity sha512-1GrJFfSevQdYpoDzx8mEE2TDWsb/zmFuY09l6hURg1AeFIKQOvZ+vH0UPjzmd1CZIbfTV5HUkMeBmFiDBkgIsQ==
+eslint-loader@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.1.2.tgz#453542a1230d6ffac90e4e7cb9cadba9d851be68"
+ integrity sha512-rA9XiXEOilLYPOIInvVH5S/hYfyTPyxag6DZhoQOduM+3TkghAEQ3VcFO8VnX4J4qg/UIBzp72aOf/xvYmpmsg==
dependencies:
loader-fs-cache "^1.0.0"
loader-utils "^1.0.2"
@@ -2311,6 +2418,14 @@ eslint-scope@^4.0.0:
esrecurse "^4.1.0"
estraverse "^4.1.1"
+eslint-scope@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.2.tgz#5f10cd6cabb1965bf479fa65745673439e21cb0e"
+ integrity sha512-5q1+B/ogmHl8+paxtOKx38Z8LtWkVGuNt3+GQNErqwLl6ViNp/gdJGMCjZNxZ8j/VYjDNZ2Fo+eQc1TAVPIzbg==
+ dependencies:
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
eslint-utils@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512"
@@ -2321,57 +2436,56 @@ eslint-visitor-keys@^1.0.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==
-eslint@^5.9.0:
- version "5.9.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.9.0.tgz#b234b6d15ef84b5849c6de2af43195a2d59d408e"
- integrity sha512-g4KWpPdqN0nth+goDNICNXGfJF7nNnepthp46CAlJoJtC5K/cLu3NgCM3AHu1CkJ5Hzt9V0Y0PBAO6Ay/gGb+w==
+eslint@^5.15.1:
+ version "5.15.1"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.15.1.tgz#8266b089fd5391e0009a047050795b1d73664524"
+ integrity sha512-NTcm6vQ+PTgN3UBsALw5BMhgO6i5EpIjQF/Xb5tIh3sk9QhrFafujUOczGz4J24JBlzWclSB9Vmx8d+9Z6bFCg==
dependencies:
"@babel/code-frame" "^7.0.0"
- ajv "^6.5.3"
+ ajv "^6.9.1"
chalk "^2.1.0"
cross-spawn "^6.0.5"
debug "^4.0.1"
- doctrine "^2.1.0"
- eslint-scope "^4.0.0"
+ doctrine "^3.0.0"
+ eslint-scope "^4.0.2"
eslint-utils "^1.3.1"
eslint-visitor-keys "^1.0.0"
- espree "^4.0.0"
+ espree "^5.0.1"
esquery "^1.0.1"
esutils "^2.0.2"
- file-entry-cache "^2.0.0"
+ file-entry-cache "^5.0.1"
functional-red-black-tree "^1.0.1"
glob "^7.1.2"
globals "^11.7.0"
ignore "^4.0.6"
+ import-fresh "^3.0.0"
imurmurhash "^0.1.4"
- inquirer "^6.1.0"
- is-resolvable "^1.1.0"
+ inquirer "^6.2.2"
js-yaml "^3.12.0"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.3.0"
- lodash "^4.17.5"
+ lodash "^4.17.11"
minimatch "^3.0.4"
mkdirp "^0.5.1"
natural-compare "^1.4.0"
optionator "^0.8.2"
path-is-inside "^1.0.2"
- pluralize "^7.0.0"
progress "^2.0.0"
regexpp "^2.0.1"
- require-uncached "^1.0.3"
semver "^5.5.1"
strip-ansi "^4.0.0"
strip-json-comments "^2.0.1"
- table "^5.0.2"
+ table "^5.2.3"
text-table "^0.2.0"
-espree@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/espree/-/espree-4.0.0.tgz#253998f20a0f82db5d866385799d912a83a36634"
- integrity sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg==
+espree@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a"
+ integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==
dependencies:
- acorn "^5.6.0"
- acorn-jsx "^4.1.1"
+ acorn "^6.0.7"
+ acorn-jsx "^5.0.0"
+ eslint-visitor-keys "^1.0.0"
esprima@^4.0.0:
version "4.0.1"
@@ -2433,6 +2547,19 @@ execa@^0.10.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
+execa@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
+ integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
+ dependencies:
+ cross-spawn "^5.0.1"
+ get-stream "^3.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
execall@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/execall/-/execall-1.0.0.tgz#73d0904e395b3cab0658b08d09ec25307f29bb73"
@@ -2480,7 +2607,7 @@ extend@^3.0.0:
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
-external-editor@^3.0.0:
+external-editor@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27"
integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==
@@ -2508,16 +2635,16 @@ fast-deep-equal@^2.0.1:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
-fast-glob@^2.0.2:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.2.tgz#71723338ac9b4e0e2fff1d6748a2a13d5ed352bf"
- integrity sha512-TR6zxCKftDQnUAPvkrCWdBgDq/gbqx8A3ApnBrR5rMvpp6+KMJI0Igw7fkWPgeVK0uhRXTXdvO3O+YP0CaUX2g==
+fast-glob@^2.2.6:
+ version "2.2.6"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.6.tgz#a5d5b697ec8deda468d85a74035290a025a95295"
+ integrity sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w==
dependencies:
"@mrmlnc/readdir-enhanced" "^2.2.1"
- "@nodelib/fs.stat" "^1.0.1"
+ "@nodelib/fs.stat" "^1.1.2"
glob-parent "^3.1.0"
is-glob "^4.0.0"
- merge2 "^1.2.1"
+ merge2 "^1.2.3"
micromatch "^3.1.10"
fast-json-stable-stringify@^2.0.0:
@@ -2530,11 +2657,6 @@ fast-levenshtein@~2.0.4:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
-fastparse@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
- integrity sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=
-
figgy-pudding@^3.1.0, figgy-pudding@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
@@ -2547,13 +2669,19 @@ figures@^2.0.0:
dependencies:
escape-string-regexp "^1.0.5"
-file-entry-cache@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
- integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=
+file-entry-cache@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-4.0.0.tgz#633567d15364aefe0b299e1e217735e8f3a9f6e8"
+ integrity sha512-AVSwsnbV8vH/UVbvgEhf3saVQXORNv0ZzSkvkhQIaia5Tia+JhGTaa/ePUSVoPHQyGayQNmYfkzFi3WZV5zcpA==
dependencies:
- flat-cache "^1.2.1"
- object-assign "^4.0.1"
+ flat-cache "^2.0.1"
+
+file-entry-cache@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
+ integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==
+ dependencies:
+ flat-cache "^2.0.1"
fill-range@^4.0.0:
version "4.0.0"
@@ -2574,15 +2702,6 @@ find-cache-dir@^0.1.1:
mkdirp "^0.5.1"
pkg-dir "^1.0.0"
-find-cache-dir@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f"
- integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=
- dependencies:
- commondir "^1.0.1"
- make-dir "^1.0.0"
- pkg-dir "^2.0.0"
-
find-cache-dir@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.0.0.tgz#4c1faed59f45184530fb9d7fa123a4d04a98472d"
@@ -2614,15 +2733,29 @@ find-up@^3.0.0:
dependencies:
locate-path "^3.0.0"
-flat-cache@^1.2.1:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481"
- integrity sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=
+findup-sync@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
+ integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=
dependencies:
- circular-json "^0.3.1"
- del "^2.0.2"
- graceful-fs "^4.1.2"
- write "^0.2.1"
+ detect-file "^1.0.0"
+ is-glob "^3.1.0"
+ micromatch "^3.0.4"
+ resolve-dir "^1.0.1"
+
+flat-cache@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
+ integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==
+ dependencies:
+ flatted "^2.0.0"
+ rimraf "2.6.3"
+ write "1.0.3"
+
+flatted@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916"
+ integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==
flatten@^1.0.2:
version "1.0.2"
@@ -2642,10 +2775,10 @@ for-in@^1.0.2:
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
-formdata-polyfill@^3.0.13:
- version "3.0.13"
- resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-3.0.13.tgz#991321c83b7a760aaf3788f1b7bbbf77e85b09bb"
- integrity sha512-aYrFSz9wxtBc9E1yCfD5IFhTK9FDZVRM53kUQn1W6Et5+R9c4tpa5Mg9hQIBIc2er3fLx0ElbKujipu+2551vQ==
+formdata-polyfill@^3.0.17:
+ version "3.0.17"
+ resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-3.0.17.tgz#b82c30ee8755653927ce2b5231e9ee8a66dd448e"
+ integrity sha512-YQDARbu++HLwfbhY5a5Doo1Sk7Ib/UFct1AejQyjYyrYxVcus+Oiybest+xgSXaTnf99jNQti/hHngZwA494/Q==
fragment-cache@^0.2.1:
version "0.2.1"
@@ -2749,7 +2882,7 @@ glob-to-regexp@^0.3.0:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
-glob@^7.0.3, glob@^7.0.5, glob@^7.1.2:
+glob@^7.0.5, glob@^7.1.2, glob@^7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
@@ -2761,11 +2894,6 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.1.2:
once "^1.3.0"
path-is-absolute "^1.0.0"
-global-modules-path@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/global-modules-path/-/global-modules-path-2.3.0.tgz#b0e2bac6beac39745f7db5c59d26a36a0b94f7dc"
- integrity sha512-HchvMJNYh9dGSCy8pOQ2O8u/hoXaL+0XhnrwH0RyLiSXMMTl9W3N6KUU73+JFOg5PGjtzl6VZzUQsnrpm7Szag==
-
global-modules@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
@@ -2775,6 +2903,13 @@ global-modules@^1.0.0:
is-windows "^1.0.1"
resolve-dir "^1.0.0"
+global-modules@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
+ integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==
+ dependencies:
+ global-prefix "^3.0.0"
+
global-prefix@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
@@ -2786,35 +2921,32 @@ global-prefix@^1.0.1:
is-windows "^1.0.1"
which "^1.2.14"
+global-prefix@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97"
+ integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==
+ dependencies:
+ ini "^1.3.5"
+ kind-of "^6.0.2"
+ which "^1.3.1"
+
globals@^11.1.0, globals@^11.7.0:
version "11.7.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673"
integrity sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==
-globby@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
- integrity sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=
- dependencies:
- array-union "^1.0.1"
- arrify "^1.0.0"
- glob "^7.0.3"
- object-assign "^4.0.1"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
-
-globby@^8.0.0:
- version "8.0.1"
- resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.1.tgz#b5ad48b8aa80b35b814fc1281ecc851f1d2b5b50"
- integrity sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==
- dependencies:
- array-union "^1.0.1"
- dir-glob "^2.0.0"
- fast-glob "^2.0.2"
- glob "^7.1.2"
- ignore "^3.3.5"
- pify "^3.0.0"
- slash "^1.0.0"
+globby@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-9.0.0.tgz#3800df736dc711266df39b4ce33fe0d481f94c23"
+ integrity sha512-q0qiO/p1w/yJ0hk8V9x1UXlgsXUxlGd0AHUOXZVXBO6aznDtpx7M8D1kBrCAItoPm+4l8r6ATXV1JpjY2SBQOw==
+ dependencies:
+ array-union "^1.0.2"
+ dir-glob "^2.2.1"
+ fast-glob "^2.2.6"
+ glob "^7.1.3"
+ ignore "^4.0.3"
+ pify "^4.0.1"
+ slash "^2.0.0"
globjoin@^0.1.4:
version "0.1.4"
@@ -2833,13 +2965,6 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=
-has-ansi@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
- integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
- dependencies:
- ansi-regex "^2.0.0"
-
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -2950,17 +3075,17 @@ html-tags@^2.0.0:
resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b"
integrity sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=
-htmlparser2@^3.9.2:
- version "3.9.2"
- resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338"
- integrity sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=
+htmlparser2@^3.10.0:
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.0.tgz#5f5e422dcf6119c0d983ed36260ce9ded0bee464"
+ integrity sha512-J1nEUGv+MkXS0weHNWVKJJ+UrLfePxRWpN3C9bEi9fLxL2+ggW94DQvgYVXsaT30PGwYRIZKNZXuyMhp3Di4bQ==
dependencies:
domelementtype "^1.3.0"
domhandler "^2.3.0"
domutils "^1.5.1"
entities "^1.1.1"
inherits "^2.0.1"
- readable-stream "^2.0.2"
+ readable-stream "^3.0.6"
https-browserify@^1.0.0:
version "1.0.0"
@@ -2979,12 +3104,12 @@ icss-replace-symbols@^1.1.0:
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=
-icss-utils@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962"
- integrity sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=
+icss-utils@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.0.tgz#339dbbffb9f8729a243b701e1c29d4cc58c52f0e"
+ integrity sha512-3DEun4VOeMvSczifM3F2cKQrDQ5Pj6WKhkOq6HD4QTnDUAq8MQRxy5TX6Sy1iY6WPBe4gQ3p5vTECjbIkglkkQ==
dependencies:
- postcss "^6.0.1"
+ postcss "^7.0.14"
ieee754@^1.1.4:
version "1.1.12"
@@ -3003,12 +3128,7 @@ ignore-walk@^3.0.1:
dependencies:
minimatch "^3.0.4"
-ignore@^3.3.5:
- version "3.3.10"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
- integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==
-
-ignore@^4.0.6:
+ignore@^4.0.3, ignore@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
@@ -3025,6 +3145,14 @@ import-cwd@^2.0.0:
dependencies:
import-from "^2.1.0"
+import-fresh@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.0.0.tgz#a3d897f420cab0e671236897f75bc14b4885c390"
+ integrity sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
import-from@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1"
@@ -3083,28 +3211,28 @@ inherits@2.0.1:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
-ini@^1.3.4, ini@~1.3.0:
+ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
version "1.3.5"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
-inquirer@^6.1.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8"
- integrity sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==
+inquirer@^6.2.2:
+ version "6.2.2"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.2.tgz#46941176f65c9eb20804627149b743a218f25406"
+ integrity sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==
dependencies:
- ansi-escapes "^3.0.0"
- chalk "^2.0.0"
+ ansi-escapes "^3.2.0"
+ chalk "^2.4.2"
cli-cursor "^2.1.0"
cli-width "^2.0.0"
- external-editor "^3.0.0"
+ external-editor "^3.0.3"
figures "^2.0.0"
- lodash "^4.17.10"
+ lodash "^4.17.11"
mute-stream "0.0.7"
run-async "^2.2.0"
- rxjs "^6.1.0"
+ rxjs "^6.4.0"
string-width "^2.1.0"
- strip-ansi "^4.0.0"
+ strip-ansi "^5.0.0"
through "^2.3.6"
interpret@^1.1.0:
@@ -3119,6 +3247,11 @@ invariant@^2.2.2:
dependencies:
loose-envify "^1.0.0"
+invert-kv@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+ integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
+
invert-kv@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
@@ -3178,11 +3311,16 @@ is-binary-path@^1.0.0:
dependencies:
binary-extensions "^1.0.0"
-is-buffer@^1.1.4, is-buffer@^1.1.5:
+is-buffer@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+is-buffer@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
+ integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
+
is-builtin-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
@@ -3314,25 +3452,6 @@ is-obj@^1.0.0:
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
-is-path-cwd@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
- integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=
-
-is-path-in-cwd@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52"
- integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==
- dependencies:
- is-path-inside "^1.0.0"
-
-is-path-inside@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
- integrity sha1-jvW33lBDej/cprToZe96pVy0gDY=
- dependencies:
- path-is-inside "^1.0.1"
-
is-plain-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
@@ -3362,7 +3481,7 @@ is-regexp@^1.0.0:
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk=
-is-resolvable@^1.0.0, is-resolvable@^1.1.0:
+is-resolvable@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88"
integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==
@@ -3436,11 +3555,6 @@ js-levenshtein@^1.1.3:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-js-tokens@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
- integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
-
js-yaml@^3.12.0, js-yaml@^3.9.0:
version "3.12.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
@@ -3479,6 +3593,13 @@ json5@^0.5.0:
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=
+json5@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
+ integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
+ dependencies:
+ minimist "^1.2.0"
+
json5@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850"
@@ -3510,10 +3631,10 @@ kind-of@^6.0.0, kind-of@^6.0.2:
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
-known-css-properties@^0.10.0:
- version "0.10.0"
- resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.10.0.tgz#8378a8921e6c815ecc47095744a8900af63d577d"
- integrity sha512-OMPb86bpVbnKN/2VJw1Ggs1Hw/FNGwEL1QYiNIEHaB5FSLybJ4QD7My5Hm9yDhgpRrRnnOgu0oKeuuABzASeBw==
+known-css-properties@^0.11.0:
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.11.0.tgz#0da784f115ea77c76b81536d7052e90ee6c86a8a"
+ integrity sha512-bEZlJzXo5V/ApNNa5z375mJC6Nrz4vG43UgcSCrg2OHC+yuB6j0iDSrY7RQ/+PRofFB03wNIIt9iXIVLr4wc7w==
last-call-webpack-plugin@^3.0.0:
version "3.0.0"
@@ -3523,6 +3644,13 @@ last-call-webpack-plugin@^3.0.0:
lodash "^4.17.5"
webpack-sources "^1.1.0"
+lcid@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+ integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
+ dependencies:
+ invert-kv "^1.0.0"
+
lcid@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
@@ -3575,6 +3703,15 @@ loader-utils@^1.0.2, loader-utils@^1.1.0:
emojis-list "^2.0.0"
json5 "^0.5.0"
+loader-utils@^1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
+ integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
+ dependencies:
+ big.js "^5.2.2"
+ emojis-list "^2.0.0"
+ json5 "^1.0.1"
+
locate-path@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
@@ -3663,6 +3800,14 @@ loud-rejection@^1.0.0:
currently-unhandled "^0.4.1"
signal-exit "^3.0.0"
+lru-cache@^4.0.1:
+ version "4.1.5"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
+ integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
+ dependencies:
+ pseudomap "^1.0.2"
+ yallist "^2.1.2"
+
lru-cache@^4.1.3:
version "4.1.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c"
@@ -3678,6 +3823,11 @@ make-dir@^1.0.0:
dependencies:
pify "^3.0.0"
+mamacro@^0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4"
+ integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==
+
map-age-cleaner@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz#098fb15538fd3dbe461f12745b0ca8568d4e3f74"
@@ -3742,6 +3892,13 @@ mdn-data@~1.1.0:
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01"
integrity sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==
+mem@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76"
+ integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=
+ dependencies:
+ mimic-fn "^1.0.0"
+
mem@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/mem/-/mem-4.0.0.tgz#6437690d9471678f6cc83659c00cbafcd6b0cdaf"
@@ -3774,12 +3931,12 @@ meow@^5.0.0:
trim-newlines "^2.0.0"
yargs-parser "^10.0.0"
-merge2@^1.2.1:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.2.tgz#03212e3da8d86c4d8523cebd6318193414f94e34"
- integrity sha512-bgM8twH86rWni21thii6WCMQMRMmwqqdW3sGWi9IipnVAszdLXRjwDwAnyrVXo6DuP3AjRMMttZKUB48QWIFGg==
+merge2@^1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5"
+ integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==
-micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
+micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
@@ -3816,10 +3973,10 @@ mimic-fn@^1.0.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
-mini-css-extract-plugin@^0.4.5:
- version "0.4.5"
- resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.5.tgz#c99e9e78d54f3fa775633aee5933aeaa4e80719a"
- integrity sha512-dqBanNfktnp2hwL2YguV9Jh91PFX7gu7nRLs4TGsbAfAG6WOtlynFRYzwDwmmeSb5uIwHo9nx1ta0f7vAZVp2w==
+mini-css-extract-plugin@^0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz#ac0059b02b9692515a637115b0cc9fed3a35c7b0"
+ integrity sha512-IuaLjruM0vMKhUUT51fQdQzBYTX49dLj8w68ALEAe2A4iYNpIC4eMac67mt3NzycvjOlf07/kYxJDc0RTl1Wqw==
dependencies:
loader-utils "^1.1.0"
schema-utils "^1.0.0"
@@ -4043,6 +4200,13 @@ node-releases@^1.0.1:
dependencies:
semver "^5.3.0"
+node-releases@^1.1.8:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.8.tgz#32a63fff63c5e51b7e0f540ac95947d220fc6862"
+ integrity sha512-gQm+K9mGCiT/NXHy+V/ZZS1N/LOaGGqRAAJJs3X9Ah1g+CIbRcBgNyoNYQ+SEtcyAtB9KqDruu+fF7nWjsqRaA==
+ dependencies:
+ semver "^5.3.0"
+
nopt@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
@@ -4068,6 +4232,11 @@ normalize-path@^2.1.1:
dependencies:
remove-trailing-separator "^1.0.1"
+normalize-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
normalize-range@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
@@ -4230,6 +4399,15 @@ os-homedir@^1.0.0:
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
+os-locale@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2"
+ integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==
+ dependencies:
+ execa "^0.7.0"
+ lcid "^1.0.0"
+ mem "^1.1.0"
+
os-locale@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.0.1.tgz#3b014fbf01d87f60a1e5348d80fe870dc82c4620"
@@ -4319,6 +4497,13 @@ parallel-transform@^1.1.0:
inherits "^2.0.3"
readable-stream "^2.1.5"
+parent-module@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.0.tgz#df250bdc5391f4a085fb589dad761f5ad6b865b5"
+ integrity sha512-8Mf5juOMmiE4FcmzYc4IaiS9L3+9paz2KOiXzkRviCP6aDmN49Hz6EMWz0lGNp9pX80GvvAuLADtyGfW/Em3TA==
+ dependencies:
+ callsites "^3.0.0"
+
parse-asn1@^5.0.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8"
@@ -4387,7 +4572,7 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
-path-is-inside@^1.0.1, path-is-inside@^1.0.2:
+path-is-inside@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
@@ -4420,11 +4605,6 @@ pbkdf2@^3.0.3:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
-pify@^2.0.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
- integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
-
pify@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
@@ -4435,6 +4615,11 @@ pify@^4.0.0:
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.0.tgz#db04c982b632fd0df9090d14aaf1c8413cadb695"
integrity sha512-zrSP/KDf9DH3K3VePONoCstgPiYJy9z0SCatZuTpOc7YdnWIqwkWdXOuwlr4uDc7em8QZRsFWsT/685x5InjYg==
+pify@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
+ integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
+
pinkie-promise@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
@@ -4454,13 +4639,6 @@ pkg-dir@^1.0.0:
dependencies:
find-up "^1.0.0"
-pkg-dir@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
- integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=
- dependencies:
- find-up "^2.1.0"
-
pkg-dir@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
@@ -4468,23 +4646,18 @@ pkg-dir@^3.0.0:
dependencies:
find-up "^3.0.0"
-pluralize@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777"
- integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==
-
posix-character-classes@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
-postcss-attribute-case-insensitive@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.0.tgz#807b6a797ad8bf1c821b2d51cf641e9dd3837624"
- integrity sha512-K/zqdg0/UgUgC8qR0lDuxYzmowPpnvrrNC5YuoqzhHMubR9AuhsPlpVu3jjkLHgDAzR+ohD/m7//iGnN9WxbzQ==
+postcss-attribute-case-insensitive@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.1.tgz#b2a721a0d279c2f9103a36331c88981526428cc7"
+ integrity sha512-L2YKB3vF4PetdTIthQVeT+7YiSzMoNMLLYxPXXppOOP7NoazEAy45sh2LvJ8leCQjfBcfkYQs8TtCcQjeZTp8A==
dependencies:
postcss "^7.0.2"
- postcss-selector-parser "^5.0.0-rc.3"
+ postcss-selector-parser "^5.0.0"
postcss-calc@^6.0.0:
version "6.0.1"
@@ -4660,12 +4833,12 @@ postcss-gap-properties@^2.0.0:
dependencies:
postcss "^7.0.2"
-postcss-html@^0.34.0:
- version "0.34.0"
- resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.34.0.tgz#9bfd637ad8c3d3a43625b5ef844dc804b3370868"
- integrity sha512-BIW982Kbf9/RikInNhNS3/GA6x/qY/+jhVS9KumqXZtU9ss8Yq15HhPJ6mnaXcU5bFq2ULxpOv96mHPAErpGMQ==
+postcss-html@^0.36.0:
+ version "0.36.0"
+ resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.36.0.tgz#b40913f94eaacc2453fd30a1327ad6ee1f88b204"
+ integrity sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==
dependencies:
- htmlparser2 "^3.9.2"
+ htmlparser2 "^3.10.0"
postcss-image-set-function@^3.0.1:
version "3.0.1"
@@ -4683,14 +4856,12 @@ postcss-initial@^3.0.0:
lodash.template "^4.2.4"
postcss "^7.0.2"
-postcss-jsx@^0.35.0:
- version "0.35.0"
- resolved "https://registry.yarnpkg.com/postcss-jsx/-/postcss-jsx-0.35.0.tgz#1d6cb82393994cdc7e9aa421648e3f0f3f98209b"
- integrity sha512-AU2/9QDmHYJRxTiniMt2bJ9fwCzVF6n00VnR4gdnFGHeXRW2mGwoptpuPgYjfivkdI8LlNIuo+w8TyS6a4JhJw==
+postcss-jsx@^0.36.0:
+ version "0.36.0"
+ resolved "https://registry.yarnpkg.com/postcss-jsx/-/postcss-jsx-0.36.0.tgz#b7685ed3d070a175ef0aa48f83d9015bd772c82d"
+ integrity sha512-/lWOSXSX5jlITCKFkuYU2WLFdrncZmjSVyNpHAunEgirZXLwI8RjU556e3Uz4mv0WVHnJA9d3JWb36lK9Yx99g==
dependencies:
- "@babel/core" "^7.1.2"
- optionalDependencies:
- postcss-styled ">=0.34.0"
+ "@babel/core" ">=7.1.0"
postcss-lab-function@^2.0.1:
version "2.0.1"
@@ -4733,12 +4904,12 @@ postcss-logical@^3.0.0:
dependencies:
postcss "^7.0.2"
-postcss-markdown@^0.34.0:
- version "0.34.0"
- resolved "https://registry.yarnpkg.com/postcss-markdown/-/postcss-markdown-0.34.0.tgz#7a043e6eee3ab846a4cefe3ab43d141038e2da79"
- integrity sha512-cKPggF9OMOKPoqDm5YpYszCqMsImFh78FK6P8p6IsEKZB6IkUJYKz0/QgadYy4jLb60jcFIHJ6v6jsMH7/ZQrA==
+postcss-markdown@^0.36.0:
+ version "0.36.0"
+ resolved "https://registry.yarnpkg.com/postcss-markdown/-/postcss-markdown-0.36.0.tgz#7f22849ae0e3db18820b7b0d5e7833f13a447560"
+ integrity sha512-rl7fs1r/LNSB2bWRhyZ+lM/0bwKv9fhl38/06gF6mKMo/NPnp55+K1dSTosSVjFZc0e1ppBlu+WT91ba0PMBfQ==
dependencies:
- remark "^9.0.0"
+ remark "^10.0.1"
unist-util-find-all-after "^1.0.2"
postcss-media-minmax@^4.0.0:
@@ -4814,36 +4985,37 @@ postcss-minify-selectors@^4.0.0:
postcss "^6.0.0"
postcss-selector-parser "^3.0.0"
-postcss-modules-extract-imports@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85"
- integrity sha1-ZhQOzs447wa/DT41XWm/WdFB6oU=
+postcss-modules-extract-imports@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e"
+ integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==
dependencies:
- postcss "^6.0.1"
+ postcss "^7.0.5"
-postcss-modules-local-by-default@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069"
- integrity sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=
+postcss-modules-local-by-default@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz#dd9953f6dd476b5fd1ef2d8830c8929760b56e63"
+ integrity sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==
dependencies:
- css-selector-tokenizer "^0.7.0"
- postcss "^6.0.1"
+ postcss "^7.0.6"
+ postcss-selector-parser "^6.0.0"
+ postcss-value-parser "^3.3.1"
-postcss-modules-scope@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90"
- integrity sha1-1upkmUx5+XtipytCb75gVqGUu5A=
+postcss-modules-scope@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb"
+ integrity sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==
dependencies:
- css-selector-tokenizer "^0.7.0"
- postcss "^6.0.1"
+ postcss "^7.0.6"
+ postcss-selector-parser "^6.0.0"
-postcss-modules-values@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20"
- integrity sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=
+postcss-modules-values@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz#479b46dc0c5ca3dc7fa5270851836b9ec7152f64"
+ integrity sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==
dependencies:
icss-replace-symbols "^1.1.0"
- postcss "^6.0.1"
+ postcss "^7.0.6"
postcss-nesting@^7.0.0:
version "7.0.0"
@@ -4963,18 +5135,20 @@ postcss-place@^4.0.1:
postcss "^7.0.2"
postcss-values-parser "^2.0.0"
-postcss-preset-env@^6.4.0:
- version "6.4.0"
- resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.4.0.tgz#f5466550b177454fc98ca5054b4478e8e5caa714"
- integrity sha512-0jCyY/T9kWv1i2abt5DOOoh0uHJia0HUTWMV72Tw75tGx3pH628oSS8WBMCE5L1Ou3LvoAl9pe07u8g/afvc3A==
- dependencies:
- autoprefixer "^9.3.1"
- browserslist "^4.3.4"
- caniuse-lite "^1.0.30000905"
- css-prefers-color-scheme "^3.0.0"
- cssdb "^4.2.0"
- postcss "^7.0.5"
- postcss-attribute-case-insensitive "^4.0.0"
+postcss-preset-env@^6.6.0:
+ version "6.6.0"
+ resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.6.0.tgz#642e7d962e2bdc2e355db117c1eb63952690ed5b"
+ integrity sha512-I3zAiycfqXpPIFD6HXhLfWXIewAWO8emOKz+QSsxaUZb9Dp8HbF5kUf+4Wy/AxR33o+LRoO8blEWCHth0ZsCLA==
+ dependencies:
+ autoprefixer "^9.4.9"
+ browserslist "^4.4.2"
+ caniuse-lite "^1.0.30000939"
+ css-blank-pseudo "^0.1.4"
+ css-has-pseudo "^0.10.0"
+ css-prefers-color-scheme "^3.1.1"
+ cssdb "^4.3.0"
+ postcss "^7.0.14"
+ postcss-attribute-case-insensitive "^4.0.1"
postcss-color-functional-notation "^2.0.1"
postcss-color-gray "^5.0.0"
postcss-color-hex-alpha "^5.0.2"
@@ -5110,7 +5284,16 @@ postcss-selector-parser@^3.0.0, postcss-selector-parser@^3.1.0:
indexes-of "^1.0.1"
uniq "^1.0.1"
-postcss-selector-parser@^5.0.0-rc.3:
+postcss-selector-parser@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c"
+ integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==
+ dependencies:
+ cssesc "^2.0.0"
+ indexes-of "^1.0.1"
+ uniq "^1.0.1"
+
+postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4:
version "5.0.0-rc.4"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0-rc.4.tgz#ca5e77238bf152966378c13e91ad6d611568ea87"
integrity sha512-0XvfYuShrKlTk1ooUrVzMCFQRcypsdEIsGqh5IxC5rdtBi4/M/tDAJeSONwC2MTqEFsmPZYAV7Dd4X8rgAfV0A==
@@ -5119,10 +5302,14 @@ postcss-selector-parser@^5.0.0-rc.3:
indexes-of "^1.0.1"
uniq "^1.0.1"
-postcss-styled@>=0.34.0, postcss-styled@^0.34.0:
- version "0.34.0"
- resolved "https://registry.yarnpkg.com/postcss-styled/-/postcss-styled-0.34.0.tgz#07d47bcb13707289782aa058605fd9feaf84391d"
- integrity sha512-Uaeetr/xOiQWGJgzPFOr32/Bwykpfh9TVE26OpmwDb8eEN205TS/gqkt9ri+C6otQzQKXqbMfeZNbKYi7QpeNA==
+postcss-selector-parser@^6.0.0:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c"
+ integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==
+ dependencies:
+ cssesc "^3.0.0"
+ indexes-of "^1.0.1"
+ uniq "^1.0.1"
postcss-svgo@^4.0.0:
version "4.0.0"
@@ -5134,10 +5321,10 @@ postcss-svgo@^4.0.0:
postcss-value-parser "^3.0.0"
svgo "^1.0.0"
-postcss-syntax@^0.34.0:
- version "0.34.0"
- resolved "https://registry.yarnpkg.com/postcss-syntax/-/postcss-syntax-0.34.0.tgz#4a85c022f1cdecea72102775c91af1e7f506d83a"
- integrity sha512-L36NZwq2UK743US+vl1CRMdBRZCBmFYfThP9n9jCFhX1Wfk6BqnRSgt0Fy8q44IwxPee/GCzlo7T1c1JIeUDlQ==
+postcss-syntax@^0.36.2:
+ version "0.36.2"
+ resolved "https://registry.yarnpkg.com/postcss-syntax/-/postcss-syntax-0.36.2.tgz#f08578c7d95834574e5593a82dfbfa8afae3b51c"
+ integrity sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==
postcss-unique-selectors@^4.0.0:
version "4.0.0"
@@ -5167,7 +5354,7 @@ postcss-values-parser@^2.0.0:
indexes-of "^1.0.1"
uniq "^1.0.1"
-postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.23:
+postcss@^6.0.0:
version "6.0.23"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324"
integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==
@@ -5185,6 +5372,24 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.2:
source-map "^0.6.1"
supports-color "^5.4.0"
+postcss@^7.0.13:
+ version "7.0.13"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.13.tgz#42bf716413e8f1c786ab71dc6e722b3671b16708"
+ integrity sha512-h8SY6kQTd1wISHWjz+E6cswdhMuyBZRb16pSTv3W4zYZ3/YbyWeJdNUeOXB5IdZqE1U76OUEjjjqsC3z2f3hVg==
+ dependencies:
+ chalk "^2.4.2"
+ source-map "^0.6.1"
+ supports-color "^6.1.0"
+
+postcss@^7.0.14:
+ version "7.0.14"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5"
+ integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==
+ dependencies:
+ chalk "^2.4.2"
+ source-map "^0.6.1"
+ supports-color "^6.1.0"
+
postcss@^7.0.3, postcss@^7.0.5:
version "7.0.5"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.5.tgz#70e6443e36a6d520b0fd4e7593fcca3635ee9f55"
@@ -5194,6 +5399,15 @@ postcss@^7.0.3, postcss@^7.0.5:
source-map "^0.6.1"
supports-color "^5.5.0"
+postcss@^7.0.6:
+ version "7.0.6"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.6.tgz#6dcaa1e999cdd4a255dcd7d4d9547f4ca010cdc2"
+ integrity sha512-Nq/rNjnHFcKgCDDZYO0lNsl6YWe6U7tTy+ESN+PnLxebL8uBtYX59HZqvrj7YLK5UCyll2hqDsJOo3ndzEW8Ug==
+ dependencies:
+ chalk "^2.4.1"
+ source-map "^0.6.1"
+ supports-color "^5.5.0"
+
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@@ -5305,11 +5519,6 @@ quick-lru@^1.0.0:
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8"
integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=
-ramda@^0.25.0:
- version "0.25.0"
- resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9"
- integrity sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==
-
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80"
@@ -5365,6 +5574,15 @@ read-pkg@^3.0.0:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
+readable-stream@^3.0.6:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06"
+ integrity sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==
+ dependencies:
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
+
readdirp@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
@@ -5398,20 +5616,20 @@ regenerate-unicode-properties@^7.0.0:
dependencies:
regenerate "^1.4.0"
-regenerate@^1.2.1, regenerate@^1.4.0:
+regenerate@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
-regenerator-runtime@^0.11.1:
- version "0.11.1"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
- integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+regenerator-runtime@^0.12.0:
+ version "0.12.1"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
+ integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
-regenerator-transform@^0.13.3:
- version "0.13.3"
- resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb"
- integrity sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==
+regenerator-transform@^0.13.4:
+ version "0.13.4"
+ resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.4.tgz#18f6763cf1382c69c36df76c6ce122cc694284fb"
+ integrity sha512-T0QMBjK3J0MtxjPmdIMXm72Wvj2Abb0Bd4HADdfijwMdoIsyQZ6fWC7kDFhk2YinBBEMZDL7Y7wh0J1sGx3S4A==
dependencies:
private "^0.1.6"
@@ -5423,20 +5641,20 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
+regexp-tree@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.0.tgz#a56ad7746097888ea16457479029ec9345b96ab0"
+ integrity sha512-rHQv+tzu+0l3KS/ERabas1yK49ahNVxuH40WcPg53CzP5p8TgmmyBgHELLyJcvjhTD0e5ahSY6C76LbEVtr7cg==
+ dependencies:
+ cli-table3 "^0.5.0"
+ colors "^1.1.2"
+ yargs "^10.0.3"
+
regexpp@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==
-regexpu-core@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
- integrity sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=
- dependencies:
- regenerate "^1.2.1"
- regjsgen "^0.2.0"
- regjsparser "^0.1.4"
-
regexpu-core@^4.1.3, regexpu-core@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.2.0.tgz#a3744fa03806cffe146dea4421a3e73bdcc47b1d"
@@ -5449,23 +5667,11 @@ regexpu-core@^4.1.3, regexpu-core@^4.2.0:
unicode-match-property-ecmascript "^1.0.4"
unicode-match-property-value-ecmascript "^1.0.2"
-regjsgen@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
- integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=
-
regjsgen@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.4.0.tgz#c1eb4c89a209263f8717c782591523913ede2561"
integrity sha512-X51Lte1gCYUdlwhF28+2YMO0U6WeN0GLpgpA7LK7mbdDnkQYiwvEpmpe0F/cv5L14EbxgrdayAG3JETBv0dbXA==
-regjsparser@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
- integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=
- dependencies:
- jsesc "~0.5.0"
-
regjsparser@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.3.0.tgz#3c326da7fcfd69fa0d332575a41c8c0cdf588c96"
@@ -5473,10 +5679,10 @@ regjsparser@^0.3.0:
dependencies:
jsesc "~0.5.0"
-remark-parse@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95"
- integrity sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==
+remark-parse@^6.0.0:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-6.0.3.tgz#c99131052809da482108413f87b0ee7f52180a3a"
+ integrity sha512-QbDXWN4HfKTUC0hHa4teU463KclLAnwpn/FBn87j9cKYJWWawbiLgMfP2Q4XwhxxuuuOxHlw+pSN0OKuJwyVvg==
dependencies:
collapse-white-space "^1.0.2"
is-alphabetical "^1.0.0"
@@ -5494,10 +5700,10 @@ remark-parse@^5.0.0:
vfile-location "^2.0.0"
xtend "^4.0.1"
-remark-stringify@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-5.0.0.tgz#336d3a4d4a6a3390d933eeba62e8de4bd280afba"
- integrity sha512-Ws5MdA69ftqQ/yhRF9XhVV29mhxbfGhbz0Rx5bQH+oJcNhhSM6nCu1EpLod+DjrFGrU0BMPs+czVmJZU7xiS7w==
+remark-stringify@^6.0.0:
+ version "6.0.4"
+ resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-6.0.4.tgz#16ac229d4d1593249018663c7bddf28aafc4e088"
+ integrity sha512-eRWGdEPMVudijE/psbIDNcnJLRVx3xhfuEsTDGgH4GsFF91dVhw5nhmnBppafJ7+NWINW6C7ZwWbi30ImJzqWg==
dependencies:
ccount "^1.0.0"
is-alphanumeric "^1.0.0"
@@ -5514,14 +5720,14 @@ remark-stringify@^5.0.0:
unherit "^1.0.4"
xtend "^4.0.1"
-remark@^9.0.0:
- version "9.0.0"
- resolved "https://registry.yarnpkg.com/remark/-/remark-9.0.0.tgz#c5cfa8ec535c73a67c4b0f12bfdbd3a67d8b2f60"
- integrity sha512-amw8rGdD5lHbMEakiEsllmkdBP+/KpjW/PRK6NSGPZKCQowh0BT4IWXDAkRMyG3SB9dKPXWMviFjNusXzXNn3A==
+remark@^10.0.1:
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/remark/-/remark-10.0.1.tgz#3058076dc41781bf505d8978c291485fe47667df"
+ integrity sha512-E6lMuoLIy2TyiokHprMjcWNJ5UxfGQjaMSMhV+f4idM625UjjK4j798+gPs5mfjzDE6vL0oFKVeZM6gZVSVrzQ==
dependencies:
- remark-parse "^5.0.0"
- remark-stringify "^5.0.0"
- unified "^6.0.0"
+ remark-parse "^6.0.0"
+ remark-stringify "^6.0.0"
+ unified "^7.0.0"
remove-trailing-separator@^1.0.1:
version "1.1.0"
@@ -5558,14 +5764,6 @@ require-main-filename@^1.0.1:
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
-require-uncached@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
- integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=
- dependencies:
- caller-path "^0.1.0"
- resolve-from "^1.0.0"
-
requireindex@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.1.0.tgz#e5404b81557ef75db6e49c5a72004893fe03e162"
@@ -5578,7 +5776,7 @@ resolve-cwd@^2.0.0:
dependencies:
resolve-from "^3.0.0"
-resolve-dir@^1.0.0:
+resolve-dir@^1.0.0, resolve-dir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
@@ -5586,11 +5784,6 @@ resolve-dir@^1.0.0:
expand-tilde "^2.0.0"
global-modules "^1.0.0"
-resolve-from@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
- integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=
-
resolve-from@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
@@ -5636,7 +5829,14 @@ rgba-regex@^1.0.0:
resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
-rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
+rimraf@2.6.3:
+ version "2.6.3"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
+ integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
+ dependencies:
+ glob "^7.1.3"
+
+rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==
@@ -5665,10 +5865,10 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
-rxjs@^6.1.0:
- version "6.3.2"
- resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.2.tgz#6a688b16c4e6e980e62ea805ec30648e1c60907f"
- integrity sha512-hV7criqbR0pe7EeL3O66UYVg92IR0XsA97+9y+BWTePK9SKmEI5Qd3Zj6uPnGkNzXsBywBQWTvujPl+1Kn9Zjw==
+rxjs@^6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504"
+ integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==
dependencies:
tslib "^1.9.0"
@@ -5694,14 +5894,6 @@ sax@^1.2.4, sax@~1.2.4:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
-schema-utils@^0.4.4:
- version "0.4.7"
- resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187"
- integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==
- dependencies:
- ajv "^6.1.0"
- ajv-keywords "^3.1.0"
-
schema-utils@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"
@@ -5788,11 +5980,6 @@ simple-swizzle@^0.2.2:
dependencies:
is-arrayish "^0.3.1"
-slash@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
- integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=
-
slash@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
@@ -5805,6 +5992,15 @@ slice-ansi@1.0.0:
dependencies:
is-fullwidth-code-point "^2.0.0"
+slice-ansi@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
+ integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
+ dependencies:
+ ansi-styles "^3.2.0"
+ astral-regex "^1.0.0"
+ is-fullwidth-code-point "^2.0.0"
+
snapdragon-node@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@@ -5859,6 +6055,14 @@ source-map-support@~0.5.6:
buffer-from "^1.0.0"
source-map "^0.6.0"
+source-map-support@~0.5.9:
+ version "0.5.10"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c"
+ integrity sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==
+ dependencies:
+ buffer-from "^1.0.0"
+ source-map "^0.6.0"
+
source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
@@ -5991,6 +6195,15 @@ string-width@^1.0.1:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
+string-width@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.0.0.tgz#5a1690a57cc78211fffd9bf24bbe24d090604eb1"
+ integrity sha512-rr8CUxBbvOZDUvc5lNIJ+OC1nPVpz+Siw9VBtUjB9b6jZehZLFt0JMCZzShFHIsI8cbhm0EsNIfWJMFV3cu3Ew==
+ dependencies:
+ emoji-regex "^7.0.1"
+ is-fullwidth-code-point "^2.0.0"
+ strip-ansi "^5.0.0"
+
string_decoder@^1.0.0, string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
@@ -5998,6 +6211,13 @@ string_decoder@^1.0.0, string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
+string_decoder@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
+ integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==
+ dependencies:
+ safe-buffer "~5.1.0"
+
stringify-entities@^1.0.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-1.3.2.tgz#a98417e5471fd227b3e45d3db1861c11caf668f7"
@@ -6022,6 +6242,13 @@ strip-ansi@^4.0.0:
dependencies:
ansi-regex "^3.0.0"
+strip-ansi@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f"
+ integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==
+ dependencies:
+ ansi-regex "^4.0.0"
+
strip-bom@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
@@ -6076,20 +6303,10 @@ stylelint-config-standard@^18.2.0:
dependencies:
stylelint-config-recommended "^2.1.0"
-stylelint-webpack-plugin@^0.10.5:
- version "0.10.5"
- resolved "https://registry.yarnpkg.com/stylelint-webpack-plugin/-/stylelint-webpack-plugin-0.10.5.tgz#0b6e0d373ff5e03baa8197ebe0f2625981bd266b"
- integrity sha512-jtYx3aJ2qDMvBMswe5NRPTO7kJgAKafc6GilAkWDp/ewoAmnoxA6TsYMnIPtLECRLwXevaCPvlh2JEUMGZCoUQ==
- dependencies:
- arrify "^1.0.1"
- micromatch "^3.1.8"
- object-assign "^4.1.0"
- ramda "^0.25.0"
-
-stylelint@^9.9.0:
- version "9.9.0"
- resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-9.9.0.tgz#dde466e9b049e0bd30e912ad280f1a2ecf6efdf8"
- integrity sha512-kIuX0/9/I2mZeHz6EoFt7UpLt7Mz+ic9/PmFwKMdq4BkQHikg3FkcgAElLdAmaI8Au1JEUOS996ZFE+mwXytmA==
+stylelint@^9.10.1:
+ version "9.10.1"
+ resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-9.10.1.tgz#5f0ee3701461dff1d68284e1386efe8f0677a75d"
+ integrity sha512-9UiHxZhOAHEgeQ7oLGwrwoDR8vclBKlSX7r4fH0iuu0SfPwFaLkb1c7Q2j1cqg9P7IDXeAV2TvQML/fRQzGBBQ==
dependencies:
autoprefixer "^9.0.0"
balanced-match "^1.0.0"
@@ -6097,16 +6314,16 @@ stylelint@^9.9.0:
cosmiconfig "^5.0.0"
debug "^4.0.0"
execall "^1.0.0"
- file-entry-cache "^2.0.0"
+ file-entry-cache "^4.0.0"
get-stdin "^6.0.0"
- global-modules "^1.0.0"
- globby "^8.0.0"
+ global-modules "^2.0.0"
+ globby "^9.0.0"
globjoin "^0.1.4"
html-tags "^2.0.0"
ignore "^5.0.4"
import-lazy "^3.1.0"
imurmurhash "^0.1.4"
- known-css-properties "^0.10.0"
+ known-css-properties "^0.11.0"
leven "^2.1.0"
lodash "^4.17.4"
log-symbols "^2.0.0"
@@ -6115,11 +6332,11 @@ stylelint@^9.9.0:
micromatch "^3.1.10"
normalize-selector "^0.2.0"
pify "^4.0.0"
- postcss "^7.0.0"
- postcss-html "^0.34.0"
- postcss-jsx "^0.35.0"
+ postcss "^7.0.13"
+ postcss-html "^0.36.0"
+ postcss-jsx "^0.36.0"
postcss-less "^3.1.0"
- postcss-markdown "^0.34.0"
+ postcss-markdown "^0.36.0"
postcss-media-query-parser "^0.2.3"
postcss-reporter "^6.0.0"
postcss-resolve-nested-selector "^0.1.1"
@@ -6127,14 +6344,13 @@ stylelint@^9.9.0:
postcss-sass "^0.3.5"
postcss-scss "^2.0.0"
postcss-selector-parser "^3.1.0"
- postcss-styled "^0.34.0"
- postcss-syntax "^0.34.0"
+ postcss-syntax "^0.36.2"
postcss-value-parser "^3.3.0"
resolve-from "^4.0.0"
signal-exit "^3.0.2"
slash "^2.0.0"
specificity "^0.4.1"
- string-width "^2.1.0"
+ string-width "^3.0.0"
style-search "^0.1.0"
sugarss "^2.0.0"
svg-tags "^1.0.0"
@@ -6147,11 +6363,6 @@ sugarss@^2.0.0:
dependencies:
postcss "^7.0.2"
-supports-color@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
- integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
-
supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -6159,6 +6370,13 @@ supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0:
dependencies:
has-flag "^3.0.0"
+supports-color@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3"
+ integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==
+ dependencies:
+ has-flag "^3.0.0"
+
svg-tags@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
@@ -6194,15 +6412,15 @@ table@^5.0.0:
slice-ansi "1.0.0"
string-width "^2.1.1"
-table@^5.0.2:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/table/-/table-5.1.0.tgz#69a54644f6f01ad1628f8178715b408dc6bf11f7"
- integrity sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==
+table@^5.2.3:
+ version "5.2.3"
+ resolved "https://registry.yarnpkg.com/table/-/table-5.2.3.tgz#cde0cc6eb06751c009efab27e8c820ca5b67b7f2"
+ integrity sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==
dependencies:
- ajv "^6.5.3"
- lodash "^4.17.10"
- slice-ansi "1.0.0"
- string-width "^2.1.1"
+ ajv "^6.9.1"
+ lodash "^4.17.11"
+ slice-ansi "^2.1.0"
+ string-width "^3.0.0"
tapable@^1.0.0:
version "1.0.0"
@@ -6241,6 +6459,29 @@ terser-webpack-plugin@^1.1.0:
webpack-sources "^1.1.0"
worker-farm "^1.5.2"
+terser-webpack-plugin@^1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz#3f98bc902fac3e5d0de730869f50668561262ec8"
+ integrity sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA==
+ dependencies:
+ cacache "^11.0.2"
+ find-cache-dir "^2.0.0"
+ schema-utils "^1.0.0"
+ serialize-javascript "^1.4.0"
+ source-map "^0.6.1"
+ terser "^3.16.1"
+ webpack-sources "^1.1.0"
+ worker-farm "^1.5.2"
+
+terser@^3.16.1:
+ version "3.16.1"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-3.16.1.tgz#5b0dd4fa1ffd0b0b43c2493b2c364fd179160493"
+ integrity sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow==
+ dependencies:
+ commander "~2.17.1"
+ source-map "~0.6.1"
+ source-map-support "~0.5.9"
+
terser@^3.8.1:
version "3.10.11"
resolved "https://registry.yarnpkg.com/terser/-/terser-3.10.11.tgz#e063da74b194dde9faf0a561f3a438c549d2da3f"
@@ -6400,16 +6641,18 @@ unicode-property-aliases-ecmascript@^1.0.4:
resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz#5a533f31b4317ea76f17d807fa0d116546111dd0"
integrity sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg==
-unified@^6.0.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/unified/-/unified-6.2.0.tgz#7fbd630f719126d67d40c644b7e3f617035f6dba"
- integrity sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==
+unified@^7.0.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/unified/-/unified-7.1.0.tgz#5032f1c1ee3364bd09da12e27fdd4a7553c7be13"
+ integrity sha512-lbk82UOIGuCEsZhPj8rNAkXSDXd6p0QLzIuSsCdxrqnqU56St4eyOB+AlXsVgVeRmetPTYydIuvFfpDIed8mqw==
dependencies:
+ "@types/unist" "^2.0.0"
+ "@types/vfile" "^3.0.0"
bail "^1.0.0"
extend "^3.0.0"
is-plain-obj "^1.1.0"
trough "^1.0.0"
- vfile "^2.0.0"
+ vfile "^3.0.0"
x-is-string "^0.1.0"
union-value@^1.0.0:
@@ -6523,10 +6766,10 @@ url-loader@^1.1.2:
mime "^2.0.3"
schema-utils "^1.0.0"
-url-polyfill@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/url-polyfill/-/url-polyfill-1.1.3.tgz#ce0bdf2e923aa6f66bc198ab776323dfc5a91e62"
- integrity sha512-xIAXc0DyXJCd767sSeRu4eqisyYhR0z0sohWArCn+WPwIatD39xGrc09l+tluIUi6jGkpGa8Gz8TKwkKYxMQvQ==
+url-polyfill@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/url-polyfill/-/url-polyfill-1.1.5.tgz#bec79b72b5407dba6d8cced2e32e4ab273aa9fb1"
+ integrity sha512-9XjIJ6nwrU+nGd8t90Ze0Zs7t8A+SU0gqsqPttj6j3zAVe5q0HFcuv37nDBdVSPpi4aTHTfbUF/i+ZVD+o2EbA==
url@^0.11.0:
version "0.11.0"
@@ -6541,7 +6784,7 @@ use@^3.1.0:
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
-util-deprecate@~1.0.1:
+util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
@@ -6598,12 +6841,12 @@ vfile-message@^1.0.0:
dependencies:
unist-util-stringify-position "^1.1.1"
-vfile@^2.0.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a"
- integrity sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==
+vfile@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/vfile/-/vfile-3.0.1.tgz#47331d2abe3282424f4a4bb6acd20a44c4121803"
+ integrity sha512-y7Y3gH9BsUSdD4KzHsuMaCzRjglXN0W2EcMf0gpvu6+SbsGhMje7xDc8AEoeXy6mIwCKMI6BkjMsRjzQbhMEjQ==
dependencies:
- is-buffer "^1.1.4"
+ is-buffer "^2.0.0"
replace-ext "1.0.0"
unist-util-stringify-position "^1.0.0"
vfile-message "^1.0.0"
@@ -6624,21 +6867,22 @@ watchpack@^1.5.0:
graceful-fs "^4.1.2"
neo-async "^2.5.0"
-webpack-cli@^3.1.2:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.1.2.tgz#17d7e01b77f89f884a2bbf9db545f0f6a648e746"
- integrity sha512-Cnqo7CeqeSvC6PTdts+dywNi5CRlIPbLx1AoUPK2T6vC1YAugMG3IOoO9DmEscd+Dghw7uRlnzV1KwOe5IrtgQ==
+webpack-cli@^3.2.3:
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.2.3.tgz#13653549adfd8ccd920ad7be1ef868bacc22e346"
+ integrity sha512-Ik3SjV6uJtWIAN5jp5ZuBMWEAaP5E4V78XJ2nI+paFPh8v4HPSwo/myN0r29Xc/6ZKnd2IdrAlpSgNOu2CDQ6Q==
dependencies:
chalk "^2.4.1"
cross-spawn "^6.0.5"
enhanced-resolve "^4.1.0"
- global-modules-path "^2.3.0"
+ findup-sync "^2.0.0"
+ global-modules "^1.0.0"
import-local "^2.0.0"
interpret "^1.1.0"
loader-utils "^1.1.0"
supports-color "^5.5.0"
v8-compile-cache "^2.0.2"
- yargs "^12.0.2"
+ yargs "^12.0.4"
webpack-sources@^1.1.0:
version "1.2.0"
@@ -6656,17 +6900,17 @@ webpack-sources@^1.3.0:
source-list-map "^2.0.0"
source-map "~0.6.1"
-webpack@^4.27.1:
- version "4.27.1"
- resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.27.1.tgz#5f2e2db446d2266376fa15d7d2277a1a9c2e12bb"
- integrity sha512-WArHiLvHrlfyRM8i7f+2SFbr/XbQ0bXqTkPF8JpHOzub5482Y3wx7rEO8stuLGOKOgZJcqcisLhD7LrM/+fVMw==
- dependencies:
- "@webassemblyjs/ast" "1.7.11"
- "@webassemblyjs/helper-module-context" "1.7.11"
- "@webassemblyjs/wasm-edit" "1.7.11"
- "@webassemblyjs/wasm-parser" "1.7.11"
- acorn "^5.6.2"
- acorn-dynamic-import "^3.0.0"
+webpack@^4.29.6:
+ version "4.29.6"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.29.6.tgz#66bf0ec8beee4d469f8b598d3988ff9d8d90e955"
+ integrity sha512-MwBwpiE1BQpMDkbnUUaW6K8RFZjljJHArC6tWQJoFm0oQtfoSebtg4Y7/QHnJ/SddtjYLHaKGX64CFjG5rehJw==
+ dependencies:
+ "@webassemblyjs/ast" "1.8.5"
+ "@webassemblyjs/helper-module-context" "1.8.5"
+ "@webassemblyjs/wasm-edit" "1.8.5"
+ "@webassemblyjs/wasm-parser" "1.8.5"
+ acorn "^6.0.5"
+ acorn-dynamic-import "^4.0.0"
ajv "^6.1.0"
ajv-keywords "^3.1.0"
chrome-trace-event "^1.0.0"
@@ -6680,7 +6924,7 @@ webpack@^4.27.1:
mkdirp "~0.5.0"
neo-async "^2.5.0"
node-libs-browser "^2.0.0"
- schema-utils "^0.4.4"
+ schema-utils "^1.0.0"
tapable "^1.1.0"
terser-webpack-plugin "^1.1.0"
watchpack "^1.5.0"
@@ -6696,7 +6940,7 @@ which-module@^2.0.0:
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
-which@^1.2.14, which@^1.2.9:
+which@^1.2.14, which@^1.2.9, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -6735,10 +6979,10 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
-write@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
- integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=
+write@1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"
+ integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==
dependencies:
mkdirp "^0.5.1"
@@ -6747,16 +6991,16 @@ x-is-string@^0.1.0:
resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82"
integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=
-xregexp@4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020"
- integrity sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==
-
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
+y18n@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+ integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
+
"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
@@ -6772,20 +7016,53 @@ yallist@^3.0.0, yallist@^3.0.2:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"
integrity sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=
-yargs-parser@^10.0.0, yargs-parser@^10.1.0:
+yargs-parser@^10.0.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"
integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==
dependencies:
camelcase "^4.1.0"
-yargs@^12.0.2:
- version "12.0.2"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc"
- integrity sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==
+yargs-parser@^11.1.1:
+ version "11.1.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4"
+ integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==
+ dependencies:
+ camelcase "^5.0.0"
+ decamelize "^1.2.0"
+
+yargs-parser@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950"
+ integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==
+ dependencies:
+ camelcase "^4.1.0"
+
+yargs@^10.0.3:
+ version "10.1.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5"
+ integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==
+ dependencies:
+ cliui "^4.0.0"
+ decamelize "^1.1.1"
+ find-up "^2.1.0"
+ get-caller-file "^1.0.1"
+ os-locale "^2.0.0"
+ require-directory "^2.1.1"
+ require-main-filename "^1.0.1"
+ set-blocking "^2.0.0"
+ string-width "^2.0.0"
+ which-module "^2.0.0"
+ y18n "^3.2.1"
+ yargs-parser "^8.1.0"
+
+yargs@^12.0.4:
+ version "12.0.5"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
+ integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==
dependencies:
cliui "^4.0.0"
- decamelize "^2.0.0"
+ decamelize "^1.2.0"
find-up "^3.0.0"
get-caller-file "^1.0.1"
os-locale "^3.0.0"
@@ -6795,4 +7072,4 @@ yargs@^12.0.2:
string-width "^2.0.0"
which-module "^2.0.0"
y18n "^3.2.1 || ^4.0.0"
- yargs-parser "^10.1.0"
+ yargs-parser "^11.1.1"