修改 tgapi.HTML 编码器并补全调用 (#19),补全 IP186/javadoc (#18)

- 修订 Telegram HTML 实体转义 (#19
  - 为所有 HTML 内嵌输入补全转义代码
  - 移除了 apache-commons-text 类库
  - 添加了自己的 HTML 实体转义类
- 补充 IP186(#17) 的 javadoc (#18
This commit is contained in:
A.C.Sukazyo Eyre 2021-12-27 17:01:17 +08:00
parent e548dd1537
commit e808a37fb2
Signed by: Eyre_S
GPG Key ID: EFB47D98FE082FAD
13 changed files with 135 additions and 48 deletions

View File

@ -20,7 +20,6 @@ repositories {
dependencies { dependencies {
compileOnlyApi "com.github.spotbugs:spotbugs-annotations:${libSpotbugsVersion}" compileOnlyApi "com.github.spotbugs:spotbugs-annotations:${libSpotbugsVersion}"
implementation "org.apache.commons:commons-text:${libApacheCommonsTextVersion}"
api "cc.sukazyo:messiva:${libMessivaVersion}" api "cc.sukazyo:messiva:${libMessivaVersion}"

View File

@ -1,11 +1,10 @@
## Core ## Core
VERSION = 0.4.2.10 VERSION = 0.4.2.11
# dependencies # dependencies
libSpotbugsVersion = 4.5.2 libSpotbugsVersion = 4.5.2
libApacheCommonsTextVersion = 1.9
libMessivaVersion = 0.1.0.1 libMessivaVersion = 0.1.0.1

View File

@ -4,6 +4,6 @@ package cc.sukazyo.cono.morny;
* the final field that will be updated by gradle automatically. * the final field that will be updated by gradle automatically.
*/ */
public class GradleProjectConfigures { public class GradleProjectConfigures {
public static final String VERSION = "0.4.2.10"; public static final String VERSION = "0.4.2.11";
public static final long COMPILE_TIMESTAMP = 1640434011159L; public static final long COMPILE_TIMESTAMP = 1640595623685L;
} }

View File

@ -13,6 +13,8 @@ import com.pengrad.telegrambot.request.SendSticker;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static cc.sukazyo.cono.morny.util.StringUtils.escapeHtmlTelegram;
/** /**
* 通过 bot 呼叫主人的事件监听管理类 * 通过 bot 呼叫主人的事件监听管理类
* @since 0.4.2.1 * @since 0.4.2.1
@ -69,12 +71,15 @@ public class OnCallMe extends EventListener {
*/ */
private static void requestSteamJoin (Update event) { private static void requestSteamJoin (Update event) {
MornyCoeur.getAccount().execute(new SendMessage( MornyCoeur.getAccount().execute(new SendMessage(
ME, String.format(""" ME, String.format(
"""
request <b>STEAM LIBRARY</b> request <b>STEAM LIBRARY</b>
from <a href="tg://user?id=%d">%s</a>""", from <a href="tg://user?id=%d">%s</a>""",
event.message().from().id(), event.message().from().id(),
escapeHtmlTelegram(
event.message().from().firstName() + " " + event.message().from().lastName() event.message().from().firstName() + " " + event.message().from().lastName()
) )
)
).parseMode(ParseMode.HTML)); ).parseMode(ParseMode.HTML));
} }
@ -86,12 +91,15 @@ public class OnCallMe extends EventListener {
*/ */
private static void requestHanaParesuJoin (Update event) { private static void requestHanaParesuJoin (Update event) {
MornyCoeur.getAccount().execute(new SendMessage( MornyCoeur.getAccount().execute(new SendMessage(
ME, String.format(""" ME, String.format(
"""
request <b>Hana Paresu</b> request <b>Hana Paresu</b>
from <a href="tg://user?id=%d">%s</a>""", from <a href="tg://user?id=%d">%s</a>""",
event.message().from().id(), event.message().from().id(),
escapeHtmlTelegram(
event.message().from().firstName() + " " + event.message().from().lastName() event.message().from().firstName() + " " + event.message().from().lastName()
) )
)
).parseMode(ParseMode.HTML)); ).parseMode(ParseMode.HTML));
} }
@ -111,12 +119,15 @@ public class OnCallMe extends EventListener {
*/ */
private static void requestCustomCall (Update event) { private static void requestCustomCall (Update event) {
MornyCoeur.getAccount().execute(new SendMessage( MornyCoeur.getAccount().execute(new SendMessage(
ME, String.format(""" ME, String.format(
"""
request <u>[???]</u> request <u>[???]</u>
from <a href="tg://user?id=%d">%s</a>""", from <a href="tg://user?id=%d">%s</a>""",
event.message().from().id(), event.message().from().id(),
escapeHtmlTelegram(
event.message().from().firstName() + " " + event.message().from().lastName() event.message().from().firstName() + " " + event.message().from().lastName()
) )
)
).parseMode(ParseMode.HTML)); ).parseMode(ParseMode.HTML));
MornyCoeur.getAccount().execute(new ForwardMessage( MornyCoeur.getAccount().execute(new ForwardMessage(
ME, ME,

View File

@ -10,7 +10,6 @@ import cc.sukazyo.cono.morny.bot.event.on_commands.GetUsernameAndId;
import cc.sukazyo.cono.morny.bot.event.on_commands.Ip186Query; import cc.sukazyo.cono.morny.bot.event.on_commands.Ip186Query;
import cc.sukazyo.cono.morny.data.MornyJrrp; import cc.sukazyo.cono.morny.data.MornyJrrp;
import cc.sukazyo.cono.morny.data.TelegramStickers; import cc.sukazyo.cono.morny.data.TelegramStickers;
import cc.sukazyo.cono.morny.util.CommonFormatUtils;
import com.pengrad.telegrambot.model.Update; import com.pengrad.telegrambot.model.Update;
import com.pengrad.telegrambot.model.request.ParseMode; import com.pengrad.telegrambot.model.request.ParseMode;
import com.pengrad.telegrambot.request.SendMessage; import com.pengrad.telegrambot.request.SendMessage;
@ -19,6 +18,9 @@ import com.pengrad.telegrambot.request.SendSticker;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static cc.sukazyo.cono.morny.Log.logger; import static cc.sukazyo.cono.morny.Log.logger;
import static cc.sukazyo.cono.morny.util.CommonFormatUtils.formatDate;
import static cc.sukazyo.cono.morny.util.CommonFormatUtils.formatDuration;
import static cc.sukazyo.cono.morny.util.StringUtils.escapeHtmlTelegram;
public class OnCommandExecute extends EventListener { public class OnCommandExecute extends EventListener {
@ -117,7 +119,8 @@ public class OnCommandExecute extends EventListener {
private void onCommandVersionExec (@Nonnull Update event) { private void onCommandVersionExec (@Nonnull Update event) {
MornyCoeur.getAccount().execute(new SendMessage( MornyCoeur.getAccount().execute(new SendMessage(
event.message().chat().id(), event.message().chat().id(),
String.format(""" String.format(
"""
version: version:
- <code>%s</code> - <code>%s</code>
core md5_hash: core md5_hash:
@ -125,10 +128,10 @@ public class OnCommandExecute extends EventListener {
compile timestamp: compile timestamp:
- <code>%d</code> - <code>%d</code>
- <code>%s [UTC]</code>""", - <code>%s [UTC]</code>""",
MornySystem.VERSION, escapeHtmlTelegram(MornySystem.VERSION),
MornySystem.getJarMd5(), escapeHtmlTelegram(MornySystem.getJarMd5()),
GradleProjectConfigures.COMPILE_TIMESTAMP, GradleProjectConfigures.COMPILE_TIMESTAMP,
CommonFormatUtils.formatDate(GradleProjectConfigures.COMPILE_TIMESTAMP, 0) escapeHtmlTelegram(formatDate(GradleProjectConfigures.COMPILE_TIMESTAMP, 0))
) )
).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML));
} }
@ -160,24 +163,24 @@ public class OnCommandExecute extends EventListener {
- <code>%s [UTC]</code> - <code>%s [UTC]</code>
- [<code>%d</code>]""", - [<code>%d</code>]""",
// system // system
System.getProperty("os.name"), escapeHtmlTelegram(System.getProperty("os.name")),
System.getProperty("os.version"), escapeHtmlTelegram(System.getProperty("os.version")),
Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors(),
// java // java
System.getProperty("java.vm.name"), escapeHtmlTelegram(System.getProperty("java.vm.name")),
System.getProperty("java.version"), escapeHtmlTelegram(System.getProperty("java.version")),
// memory // memory
Runtime.getRuntime().totalMemory() / 1024 / 1024, Runtime.getRuntime().totalMemory() / 1024 / 1024,
Runtime.getRuntime().maxMemory() / 1024 / 1024, Runtime.getRuntime().maxMemory() / 1024 / 1024,
// version // version
MornySystem.VERSION, escapeHtmlTelegram(MornySystem.VERSION),
MornySystem.getJarMd5(), escapeHtmlTelegram(MornySystem.getJarMd5()),
CommonFormatUtils.formatDate(GradleProjectConfigures.COMPILE_TIMESTAMP, 0), escapeHtmlTelegram(formatDate(GradleProjectConfigures.COMPILE_TIMESTAMP, 0)),
GradleProjectConfigures.COMPILE_TIMESTAMP, GradleProjectConfigures.COMPILE_TIMESTAMP,
// continuous // continuous
CommonFormatUtils.formatDuration(System.currentTimeMillis() - MornyCoeur.coeurStartTimestamp), escapeHtmlTelegram(formatDuration(System.currentTimeMillis() - MornyCoeur.coeurStartTimestamp)),
System.currentTimeMillis() - MornyCoeur.coeurStartTimestamp, System.currentTimeMillis() - MornyCoeur.coeurStartTimestamp,
CommonFormatUtils.formatDate(MornyCoeur.coeurStartTimestamp, 0), escapeHtmlTelegram(formatDate(MornyCoeur.coeurStartTimestamp, 0)),
MornyCoeur.coeurStartTimestamp MornyCoeur.coeurStartTimestamp
) )
).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML));
@ -190,8 +193,9 @@ public class OnCommandExecute extends EventListener {
event.message().chat().id(), event.message().chat().id(),
String.format( String.format(
"<a href='tg://user?id=%d'>%s</a> 在(utc的)今天的运气指数是———— <code>%.2f%%</code> %s", "<a href='tg://user?id=%d'>%s</a> 在(utc的)今天的运气指数是———— <code>%.2f%%</code> %s",
event.message().from().id(), event.message().from().firstName(), event.message().from().id(),
jrrp, endChar escapeHtmlTelegram(event.message().from().firstName()),
jrrp, escapeHtmlTelegram(endChar)
) )
).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML));
} }

View File

@ -2,6 +2,7 @@ package cc.sukazyo.cono.morny.bot.event;
import cc.sukazyo.cono.morny.MornyCoeur; import cc.sukazyo.cono.morny.MornyCoeur;
import cc.sukazyo.cono.morny.bot.api.EventListener; import cc.sukazyo.cono.morny.bot.api.EventListener;
import cc.sukazyo.cono.morny.util.StringUtils;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.pengrad.telegrambot.model.Update; import com.pengrad.telegrambot.model.Update;
import com.pengrad.telegrambot.model.request.ParseMode; import com.pengrad.telegrambot.model.request.ParseMode;
@ -65,7 +66,7 @@ public class OnEventHackHandle extends EventListener {
logger.debug("hacked event by " + x); logger.debug("hacked event by " + x);
MornyCoeur.getAccount().execute(new SendMessage(x.fromChatId, String.format( MornyCoeur.getAccount().execute(new SendMessage(x.fromChatId, String.format(
"<code>%s</code>", "<code>%s</code>",
new GsonBuilder().setPrettyPrinting().create().toJson(update) StringUtils.escapeHtmlTelegram(new GsonBuilder().setPrettyPrinting().create().toJson(update))
)).parseMode(ParseMode.HTML).replyToMessageId((int)x.fromMessageId)); )).parseMode(ParseMode.HTML).replyToMessageId((int)x.fromMessageId));
return true; return true;
} }

View File

@ -10,6 +10,8 @@ import com.pengrad.telegrambot.request.SendMessage;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static cc.sukazyo.cono.morny.util.StringUtils.escapeHtmlTelegram;
public class OnUserSlashAction extends EventListener { public class OnUserSlashAction extends EventListener {
@Override @Override
@ -48,11 +50,11 @@ public class OnUserSlashAction extends EventListener {
event.message().chat().id(), event.message().chat().id(),
String.format( String.format(
"<a href='tg://user?id=%d'>%s</a> %s%s <a href='tg://user?id=%d'>%s</a>%s%s", "<a href='tg://user?id=%d'>%s</a> %s%s <a href='tg://user?id=%d'>%s</a>%s%s",
origin.id(), origin.firstName(), origin.id(), escapeHtmlTelegram(origin.firstName()),
verb, (useVerbSuffix?"":""), verb, escapeHtmlTelegram((useVerbSuffix?"":"")),
target.id(), (origin==target ? "自己" : target.firstName()), target.id(), escapeHtmlTelegram((origin==target ? "自己" : target.firstName())),
(hasObject ? (useObjectPrefix ?"": " ") : ""), escapeHtmlTelegram((hasObject ? (useObjectPrefix ?"": " ") : "")),
(hasObject ? object : "") escapeHtmlTelegram((hasObject ? object : ""))
) )
).parseMode(ParseMode.HTML)); ).parseMode(ParseMode.HTML));

View File

@ -10,6 +10,8 @@ import com.pengrad.telegrambot.response.GetChatMemberResponse;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static cc.sukazyo.cono.morny.util.StringUtils.escapeHtmlTelegram;
public class GetUsernameAndId { public class GetUsernameAndId {
public static void exec (@Nonnull String[] args, @Nonnull Update event) { public static void exec (@Nonnull String[] args, @Nonnull Update event) {
@ -65,7 +67,7 @@ public class GetUsernameAndId {
username : username :
- <code>%s</code>""", - <code>%s</code>""",
user.username() escapeHtmlTelegram(user.username())
)); ));
} }
if (user.firstName() == null) { if (user.firstName() == null) {
@ -76,7 +78,7 @@ public class GetUsernameAndId {
firstname : firstname :
- <code>%s</code>""", - <code>%s</code>""",
user.firstName() escapeHtmlTelegram(user.firstName())
)); ));
} }
if (user.lastName() == null) { if (user.lastName() == null) {
@ -87,7 +89,7 @@ public class GetUsernameAndId {
lastname : lastname :
- <code>%s</code>""", - <code>%s</code>""",
user.lastName() escapeHtmlTelegram(user.lastName())
)); ));
} }
if (user.languageCode() != null) { if (user.languageCode() != null) {
@ -96,7 +98,7 @@ public class GetUsernameAndId {
language-code : language-code :
- <code>%s</code>""", - <code>%s</code>""",
user.languageCode() escapeHtmlTelegram(user.languageCode())
)); ));
} }

View File

@ -7,10 +7,15 @@ import cc.sukazyo.cono.morny.data.ip186.IP186QueryHandler;
import com.pengrad.telegrambot.model.Update; import com.pengrad.telegrambot.model.Update;
import com.pengrad.telegrambot.model.request.ParseMode; import com.pengrad.telegrambot.model.request.ParseMode;
import com.pengrad.telegrambot.request.SendMessage; import com.pengrad.telegrambot.request.SendMessage;
import org.apache.commons.text.StringEscapeUtils;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static cc.sukazyo.cono.morny.util.StringUtils.escapeHtmlTelegram;
/**
* {@value IP186QueryHandler#SITE_URL} 查询的 telegram 命令前端
* @since 0.4.2.10
*/
public class Ip186Query { public class Ip186Query {
public static void exec (@Nonnull Update event, @Nonnull InputCommand command) { public static void exec (@Nonnull Update event, @Nonnull InputCommand command) {
@ -33,12 +38,12 @@ public class Ip186Query {
}; };
MornyCoeur.getAccount().execute(new SendMessage( MornyCoeur.getAccount().execute(new SendMessage(
event.message().chat().id(), event.message().chat().id(),
response.url() + "\n<code>" + StringEscapeUtils.escapeHtml4(response.body()) + "</code>" escapeHtmlTelegram(response.url()) + "\n<code>" + escapeHtmlTelegram(response.body()) + "</code>"
).parseMode(ParseMode.HTML).replyToMessageId(event.message().messageId())); ).parseMode(ParseMode.HTML).replyToMessageId(event.message().messageId()));
} catch (Exception e) { } catch (Exception e) {
MornyCoeur.getAccount().execute(new SendMessage( MornyCoeur.getAccount().execute(new SendMessage(
event.message().chat().id(), event.message().chat().id(),
"[Exception] in query:\n<code>" + e.getMessage() + "</code>" "[Exception] in query:\n<code>" + escapeHtmlTelegram(e.getMessage()) + "</code>"
).parseMode(ParseMode.HTML).replyToMessageId(event.message().messageId())); ).parseMode(ParseMode.HTML).replyToMessageId(event.message().messageId()));
} }

View File

@ -12,10 +12,32 @@ import com.pengrad.telegrambot.model.User;
*/ */
public class MornyJrrp { public class MornyJrrp {
/**
* 通过 telegram 用户和时间戳作为参数获取 jrrp.
*
* @see #calcJrrpXmomi 当前版本的实现算法 {@code Xmomi}
* @since 0.4.2.9
* @param user telegram 用户
* @param timestamp 时间戳
* @return 通过当前版本的算法计算出的用户 jrrp 取值为 {@code [0.00, 100.00]}
*/
public static double getJrrpFromTelegramUser (User user, long timestamp) { public static double getJrrpFromTelegramUser (User user, long timestamp) {
return calcJrrpXmomi(user.id(), timestamp / (1000 * 60 * 60 * 24)) * 100.0; return calcJrrpXmomi(user.id(), timestamp / (1000 * 60 * 60 * 24)) * 100.0;
} }
/**
* {@code Xmomi} 版本的 jrrp 算法.
* <p>
* 算法规则为将用户id与日期戳链接为 <u><code>uid@daystamp</code></u> 这样的字符串
* 然后通过 MD5 计算出字符串的哈希值取哈希值前4个字节将其作为16进制数值表示法转换为取值为 {@code [0x0000, 0xffff]} 的数值
* 得到的数值除以区间最大值 {@code 0xffff} 即可得到一个分布在 {@code [0.0, 1.0]} 之间的分布值
* 这个分布值乘以 {@code 100.0}即为计算得到的 jrrp 数值
*
* @since 0.4.2.9
* @param userId telegram 用户 uid
* @param dayStamp unix 时间戳转换为日期单位后的数值. 数值应该在转换前转换时区
* @return 算法得到的 jrrp 取值为 {@code [0.00. 100.00]}
*/
public static double calcJrrpXmomi (long userId, long dayStamp) { public static double calcJrrpXmomi (long userId, long dayStamp) {
return (double)Long.parseLong(EncryptUtils.encryptByMD5(userId + "@" + dayStamp).substring(0, 4), 16) / (double)0xffff; return (double)Long.parseLong(EncryptUtils.encryptByMD5(userId + "@" + dayStamp).substring(0, 4), 16) / (double)0xffff;
} }

View File

@ -8,20 +8,55 @@ import okhttp3.ResponseBody;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
/**
* 通过 {@value #SITE_URL} 进行 {@link #queryIp ip}/{@link #queryWhois whois} 数据查询的工具类
*
* @since 0.4.2.10
*/
public class IP186QueryHandler { public class IP186QueryHandler {
/**
* 请求所使用的 HTTP API 站点链接
* @since 0.4.2.10
*/
public static final String SITE_URL = "https://ip.186526.xyz/"; public static final String SITE_URL = "https://ip.186526.xyz/";
/**
* 进行 {@link #queryIp ip 查询}时所使用的 API 参数.<br>
* 目的使 API 直接返回原始数据
*/
private static final String QUERY_IP_PARAM = "type=json&format=true"; private static final String QUERY_IP_PARAM = "type=json&format=true";
/**
* 进行 {@link #queryWhois whois 查询}时所使用的 API 参数.<br>
* 目的使 API 直接返回原始数据
*/
private static final String QUERY_WHOIS_PARAM = "type=plain"; private static final String QUERY_WHOIS_PARAM = "type=plain";
/** 请求时使用的 OkHttp 请求工具实例 */
private static final OkHttpClient httpClient = new OkHttpClient(); private static final OkHttpClient httpClient = new OkHttpClient();
/**
* 通过 {@value #SITE_URL} 获取 ip 信息.
* @see #QUERY_IP_PARAM 发送请求时所使用的 API 参数
* @param ip 需要进行查询的 ip
* @return 查询结果data 根据 {@value #SITE_URL} 的规则以 json 序列化
* @throws IOException 任何请求或解析错误
*/
@Nonnull
public static IP186QueryResponse queryIp (String ip) throws IOException { public static IP186QueryResponse queryIp (String ip) throws IOException {
final String requestUrl = SITE_URL + ip; final String requestUrl = SITE_URL + ip;
return commonQuery(requestUrl, QUERY_IP_PARAM); return commonQuery(requestUrl, QUERY_IP_PARAM);
} }
/**
* 通过 {@value #SITE_URL} 获取域名信息.
* @see #QUERY_WHOIS_PARAM 发送请求时所使用的 API 参数
* @param domain 需要进行查询的域名
* @return 查询结果data 根据 {@value #SITE_URL} 的规则以 plain 序列化
* @throws IOException 任何请求或解析错误
*/
@Nonnull
public static IP186QueryResponse queryWhois (String domain) throws IOException { public static IP186QueryResponse queryWhois (String domain) throws IOException {
final String requestUrl = SITE_URL + "whois/" + domain; final String requestUrl = SITE_URL + "whois/" + domain;
return commonQuery(requestUrl, QUERY_WHOIS_PARAM); return commonQuery(requestUrl, QUERY_WHOIS_PARAM);

View File

@ -1,4 +1,11 @@
package cc.sukazyo.cono.morny.data.ip186; package cc.sukazyo.cono.morny.data.ip186;
/**
* {@link IP186QueryHandler} 的请求结果数据的通用封装类.
*
* @since 0.4.2.10
* @param url 请求数据的<u>人类可读的</u>来源链接<b>并非api链接</b>
* @param body API 传回的数据内容
*/
public record IP186QueryResponse(String url, String body) { public record IP186QueryResponse(String url, String body) {
} }

View File

@ -3,17 +3,9 @@ package cc.sukazyo.cono.morny.util;
import javax.annotation.Nonnegative; import javax.annotation.Nonnegative;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
public class StringUtils { public class StringUtils {
@Nonnull
public static String repeatChar (char c, int i) {
final char[] chars = new char[i];
Arrays.fill(chars, c);
return new String(chars);
}
@Nonnull @Nonnull
public static String[] formatCommand (@Nonnull String com) { public static String[] formatCommand (@Nonnull String com) {
@ -66,4 +58,12 @@ public class StringUtils {
return builder.toString(); return builder.toString();
} }
@Nonnull
public static String escapeHtmlTelegram (String raw) {
raw = raw.replaceAll("&", "&amp;");
raw = raw.replaceAll("<", "&lt;");
raw = raw.replaceAll(">", "&gt;");
return raw;
}
} }