diff --git a/pom.xml b/pom.xml index 4dcac6d..8bb2cb6 100644 --- a/pom.xml +++ b/pom.xml @@ -47,11 +47,6 @@ config 1.3.2 - - com.jagrosh - Vortex-Pro - 0.2 - diff --git a/src/main/java/com/jagrosh/vortex/Vortex.java b/src/main/java/com/jagrosh/vortex/Vortex.java index 38591d1..c2d9b7e 100644 --- a/src/main/java/com/jagrosh/vortex/Vortex.java +++ b/src/main/java/com/jagrosh/vortex/Vortex.java @@ -22,8 +22,6 @@ import com.jagrosh.vortex.commands.tools.*; import com.jagrosh.vortex.commands.owner.*; import com.jagrosh.vortex.commands.settings.*; -import java.nio.file.*; -import java.util.List; import java.util.concurrent.Executors; import com.jagrosh.jdautilities.command.CommandClient; import com.jagrosh.jdautilities.command.CommandClientBuilder; @@ -84,10 +82,10 @@ config.getString("database.password")); uploader = new TextUploader(this, config.getLong("uploader.guild"), config.getLong("uploader.category")); modlog = new ModLogger(this); - basiclog = new BasicLogger(this); + basiclog = new BasicLogger(this, config); messages = new MessageCache(); logwebhook = new WebhookClientBuilder(config.getString("webhook-url")).build(); - automod = new AutoMod(this, config.getString("url-resolver.url"), config.getString("url-resolver.secret")); + automod = new AutoMod(this, config); strikehandler = new StrikeHandler(this); CommandClient client = new CommandClientBuilder() .setPrefix(Constants.PREFIX) diff --git a/src/main/java/com/jagrosh/vortex/automod/AutoMod.java b/src/main/java/com/jagrosh/vortex/automod/AutoMod.java index ad1154c..ab5f8d7 100644 --- a/src/main/java/com/jagrosh/vortex/automod/AutoMod.java +++ b/src/main/java/com/jagrosh/vortex/automod/AutoMod.java @@ -20,9 +20,11 @@ import com.jagrosh.vortex.database.managers.AutomodManager; import com.jagrosh.vortex.database.managers.AutomodManager.AutomodSettings; import com.jagrosh.vortex.logging.MessageCache.CachedMessage; -import com.jagrosh.vortex.pro.URLResolver; +import com.jagrosh.vortex.logging.URLResolver; +import com.jagrosh.vortex.logging.URLResolver.*; import com.jagrosh.vortex.utils.FixedCache; import com.jagrosh.vortex.utils.OtherUtil; +import com.typesafe.config.Config; import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.ArrayList; @@ -50,7 +52,6 @@ private static final Pattern INVITES = Pattern.compile("discord\\s?(?:(?:\\.|dot|\\(\\.\\)|\\(dot\\))\\s?gg|app\\s?\\.\\s?com\\s?\\/\\s?invite)\\s?\\/\\s?([A-Z0-9-]{2,18})", Pattern.CASE_INSENSITIVE); - private static final Pattern REF = Pattern.compile("https?:\\/\\/\\S+(?:\\/ref\\/|[?&#]ref(?:errer|erral)?=)\\S+", Pattern.CASE_INSENSITIVE); private static final Pattern BASE_URL = Pattern.compile("https?:\\/\\/(?:[^?&:\\/\\s]+\\.)?([^?&:\\/\\s]+\\.\\w+)(?:\\W|$)", Pattern.CASE_INSENSITIVE); @@ -70,10 +71,10 @@ private final FixedCache spams = new FixedCache<>(3000); private final HashMap latestGuildJoin = new HashMap<>(); - public AutoMod(Vortex vortex, String url, String secret) + public AutoMod(Vortex vortex, Config config) { this.vortex = vortex; - urlResolver = new URLResolver(url, secret); + urlResolver = config.getBoolean("url-resolver.active") ? new ActiveURLResolver(config) : new DummyURLResolver(); loadCopypastas(); loadReferralDomains(); } diff --git a/src/main/java/com/jagrosh/vortex/logging/AvatarSaver.java b/src/main/java/com/jagrosh/vortex/logging/AvatarSaver.java new file mode 100644 index 0000000..f3aae14 --- /dev/null +++ b/src/main/java/com/jagrosh/vortex/logging/AvatarSaver.java @@ -0,0 +1,157 @@ +/* + * Copyright 2018 John Grosh (john.a.grosh@gmail.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jagrosh.vortex.logging; + +import com.typesafe.config.Config; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import javax.imageio.ImageIO; +import net.dv8tion.jda.core.entities.User; + +/** + * + * @author John Grosh (john.a.grosh@gmail.com) + */ +public class AvatarSaver +{ + private final static BufferedImage NOAVATAR = loadNoAvatar(); + + private final String userAgent; + + public AvatarSaver(Config config) + { + userAgent = config.getString("avatar-saver.user-agent"); + } + + public byte[] makeAvatarImage(User user, String oldAvatarUrl, String oldAvatarId) + { + BufferedImage oldimg; + if(oldAvatarUrl==null) + oldimg = imageFromUrl(user.getDefaultAvatarUrl()); + else + { + oldimg = imageFromId(user.getIdLong(), oldAvatarId); + if(oldimg==null) + oldimg = imageFromUrl(oldAvatarUrl); + } + if(oldimg==null) + oldimg = NOAVATAR; + BufferedImage newimg = imageFromUrl(user.getEffectiveAvatarUrl()); + if(newimg == null) + newimg = NOAVATAR; + else if(user.getAvatarId()!=null) + saveImageWithId(newimg, user.getIdLong(), user.getAvatarId()); + BufferedImage combo = new BufferedImage(256,128,BufferedImage.TYPE_INT_ARGB_PRE); + Graphics2D g2d = combo.createGraphics(); + g2d.setColor(Color.BLACK); + if(oldimg!=null) + { + g2d.drawImage(oldimg, 0, 0, 128, 128, null); + } + if(newimg!=null) + { + g2d.drawImage(newimg, 128, 0, 128, 128, null); + } + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) + { + ImageIO.write(combo, "png", baos ); + baos.flush(); + return baos.toByteArray(); + } + catch(IOException ex) + { + return null; + } + finally + { + g2d.dispose(); + } + } + + public BufferedImage imageFromUrl(String url) + { + if(url==null) + return null; + try + { + URL u = new URL(url.replace(".gif", ".png")); + URLConnection urlConnection = u.openConnection(); + urlConnection.setRequestProperty("user-agent", userAgent); + return ImageIO.read(urlConnection.getInputStream()); + } + catch(IOException|IllegalArgumentException e) + { + return null; + } + } + + private BufferedImage imageFromId(long id, String avyId) + { + try + { + return ImageIO.read(location(id, avyId)); + } + catch(IOException ex) + { + return null; + } + } + + private void saveImageWithId(BufferedImage img, long id, String avyId) + { + try + { + BufferedImage buf = new BufferedImage(64, 64, BufferedImage.TYPE_INT_RGB); + buf.getGraphics().drawImage(img, 0, 0, 64, 64, null); + ImageIO.write(buf, "jpg", location(id, avyId)); + buf.getGraphics().dispose(); + } + catch(IOException ex) {} + } + + private File location(long id, String avyId) + { + String dir = "avatars" + File.separator; + long remainder = id; + for(int i=16; i>=0; i-=2) + { + dir += (remainder / (long)Math.pow(10, i)) + File.separator; + remainder %= (long)Math.pow(10, i); + File directory = new File(dir); + if(!directory.exists()) + directory.mkdir(); + } + return new File(dir + avyId + ".jpg"); + } + + private static BufferedImage loadNoAvatar() + { + try + { + return ImageIO.read(new File("images"+File.separator+"NoAvatar.png")); + } + catch(IOException ex) + { + return null; + } + } +} diff --git a/src/main/java/com/jagrosh/vortex/logging/BasicLogger.java b/src/main/java/com/jagrosh/vortex/logging/BasicLogger.java index 5d9842f..a4b48c6 100644 --- a/src/main/java/com/jagrosh/vortex/logging/BasicLogger.java +++ b/src/main/java/com/jagrosh/vortex/logging/BasicLogger.java @@ -15,11 +15,11 @@ */ package com.jagrosh.vortex.logging; -import com.jagrosh.vortex.pro.AvatarUtil; import com.jagrosh.vortex.Vortex; import com.jagrosh.vortex.logging.MessageCache.CachedMessage; import com.jagrosh.vortex.utils.FormatUtil; import com.jagrosh.vortex.utils.LogUtil; +import com.typesafe.config.Config; import java.awt.Color; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; @@ -61,10 +61,12 @@ private final static String AVATAR = "\uD83D\uDDBC"; // 🖼 private final Vortex vortex; + private final AvatarSaver avatarSaver; - public BasicLogger(Vortex vortex) + public BasicLogger(Vortex vortex, Config config) { this.vortex = vortex; + this.avatarSaver = new AvatarSaver(config); } private void log(OffsetDateTime now, TextChannel tc, String emote, String message, MessageEmbed embed) @@ -300,7 +302,7 @@ OffsetDateTime now = OffsetDateTime.now(); vortex.getThreadpool().execute(() -> { - byte[] im = AvatarUtil.makeAvatarImage(event.getUser(), event.getOldAvatarUrl(), event.getOldAvatarId()); + byte[] im = avatarSaver.makeAvatarImage(event.getUser(), event.getOldAvatarUrl(), event.getOldAvatarId()); if(im!=null) logs.forEach(tc -> logFile(now, tc, AVATAR, FormatUtil.formatFullUser(event.getUser())+" has changed avatars" +(event.getUser().getAvatarId()!=null && event.getUser().getAvatarId().startsWith("a_") ? " <:gif:314068430624129039>" : "") diff --git a/src/main/java/com/jagrosh/vortex/logging/URLResolver.java b/src/main/java/com/jagrosh/vortex/logging/URLResolver.java new file mode 100644 index 0000000..2fb2ad4 --- /dev/null +++ b/src/main/java/com/jagrosh/vortex/logging/URLResolver.java @@ -0,0 +1,133 @@ +/* + * Copyright 2018 John Grosh (john.a.grosh@gmail.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jagrosh.vortex.logging; + +import com.jagrosh.vortex.utils.FixedCache; +import com.jagrosh.vortex.utils.OtherUtil; +import com.typesafe.config.Config; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import okhttp3.FormBody; +import okhttp3.OkHttpClient; +import okhttp3.Request; + +/** + * + * @author John Grosh (john.a.grosh@gmail.com) + */ +public interface URLResolver +{ + public List findRedirects(String url); + public void loadSafeDomains(); + + public static class DummyURLResolver implements URLResolver + { + @Override + public List findRedirects(String url) + { + return Collections.EMPTY_LIST; + } + + @Override + public void loadSafeDomains() {} + } + + public static class ActiveURLResolver implements URLResolver + { + private final String prefix, suffix, form; + private final OkHttpClient client = new OkHttpClient.Builder().build(); + private final Request.Builder request; + + private final FixedCache> cache = new FixedCache<>(1000); + + public ActiveURLResolver(Config config) + { + prefix = config.getString("url-resolver.prefix"); + suffix = config.getString("url-resolver.suffix"); + form = config.getString("url-resolver.form"); + request = new Request.Builder().url(config.getString("url-resolver.url")) + .header("Content-Type", "application/x-www-form-urlencoded") + .header(config.getString("url-resolver.key"), config.getString("url-resolver.value")); + } + + @Override + public synchronized List findRedirects(String url) + { + if(isSafeDomain(url)) + return Collections.EMPTY_LIST; + if(cache.contains(url)) + return cache.get(url); + try + { + List resolved = resolve(client + .newCall(request.post(new FormBody.Builder().add(form, url).build()).build()) + .execute().body().string()); + cache.put(url, resolved); + System.out.println("Link Resolving: "+url+" -> "+resolved); + return resolved; + } + catch(Exception ex) + { + return Collections.EMPTY_LIST; + } + } + + private List resolve(String text) + { + List list = new LinkedList<>(); + boolean skip = true; // first link is always the link we gave + for(int i=0; i