diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/audit/http/HashUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/audit/http/HashUtil.java new file mode 100644 index 00000000..d912457c --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/audit/http/HashUtil.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@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.mybatisflex.core.audit.http; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; + +public class HashUtil { + private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray(); + + public static String md5(String srcStr) { + return hash("MD5", srcStr); + } + + public static String sha256(String srcStr) { + return hash("SHA-256", srcStr); + } + + public static String hash(String algorithm, String srcStr) { + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + byte[] bytes = md.digest(srcStr.getBytes(StandardCharsets.UTF_8)); + return toHex(bytes); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String toHex(byte[] bytes) { + StringBuilder ret = new StringBuilder(bytes.length * 2); + for (byte b : bytes) { + ret.append(HEX_DIGITS[(b >> 4) & 0x0f]); + ret.append(HEX_DIGITS[b & 0x0f]); + } + return ret.toString(); + } + +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/audit/http/HttpMessageReporter.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/audit/http/HttpMessageReporter.java new file mode 100644 index 00000000..8c30bd1d --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/audit/http/HttpMessageReporter.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@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.mybatisflex.core.audit.http; + +import com.mybatisflex.core.audit.AuditMessage; +import com.mybatisflex.core.audit.MessageReporter; + +import java.util.List; + +public class HttpMessageReporter implements MessageReporter { + + private String endpoint; + private String secretKey; + private JSONFormatter jsonFormatter; + + public HttpMessageReporter(String endpoint, String secretKey, JSONFormatter jsonFormatter) { + this.endpoint = endpoint; + this.secretKey = secretKey; + this.jsonFormatter = jsonFormatter; + } + + @Override + public void sendMessages(List messages) { + long timeMillis = System.currentTimeMillis(); + String sign = HashUtil.md5(secretKey + timeMillis); + String url = endpoint + "?time=" + timeMillis + "&sign=" + sign; + HttpUtil.post(url, jsonFormatter.toJSONString(messages)); + } + + interface JSONFormatter { + String toJSONString(Object object); + } + +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/audit/http/HttpUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/audit/http/HttpUtil.java new file mode 100644 index 00000000..db86068d --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/audit/http/HttpUtil.java @@ -0,0 +1,227 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@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.mybatisflex.core.audit.http; + +import com.mybatisflex.core.util.StringUtil; +import org.apache.ibatis.logging.LogFactory; + +import javax.net.ssl.*; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Map; +import java.util.Map.Entry; + + +public class HttpUtil { + + private static final String POST = "POST"; + + + private static String CHARSET = "UTF-8"; + private static int connectTimeout = 15000; // 连接超时,单位毫秒 + private static int readTimeout = 15000; // 读取超时,单位毫秒 + + private static final SSLSocketFactory sslSocketFactory = initSSLSocketFactory(); + + private static final TrustAnyHostnameVerifier trustAnyHostnameVerifier = new TrustAnyHostnameVerifier(); + + /** + * https 域名校验 + */ + private static class TrustAnyHostnameVerifier implements HostnameVerifier { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + } + + /** + * https 证书管理 + */ + private static class TrustAnyTrustManager implements X509TrustManager { + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + } + + + private static SSLSocketFactory initSSLSocketFactory() { + try { + TrustManager[] tm = {new HttpUtil.TrustAnyTrustManager()}; + SSLContext sslContext = SSLContext.getInstance("TLS"); // ("TLS", "SunJSSE"); + sslContext.init(null, tm, new java.security.SecureRandom()); + return sslContext.getSocketFactory(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void setCharSet(String charSet) { + if (StringUtil.isBlank(charSet)) { + throw new IllegalArgumentException("charSet can not be blank."); + } + HttpUtil.CHARSET = charSet; + } + + public static void setConnectTimeout(int connectTimeout) { + HttpUtil.connectTimeout = connectTimeout; + } + + public static void setReadTimeout(int readTimeout) { + HttpUtil.readTimeout = readTimeout; + } + + private static HttpURLConnection getHttpConnection(String url, String method, Map headers) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException { + URL _url = new URL(url); + HttpURLConnection conn = (HttpURLConnection) _url.openConnection(); + if (conn instanceof HttpsURLConnection) { + ((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory); + ((HttpsURLConnection) conn).setHostnameVerifier(trustAnyHostnameVerifier); + } + + conn.setRequestMethod(method); + conn.setDoOutput(true); + conn.setDoInput(true); + + conn.setConnectTimeout(connectTimeout); + conn.setReadTimeout(readTimeout); + + conn.setRequestProperty("Content-Type", "application/json; charset=utf-8"); + + if (headers != null && !headers.isEmpty()) { + for (Entry entry : headers.entrySet()) { + conn.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + + return conn; + } + + + /** + * Send POST request + */ + public static String post(String url, Map queryParas, String data, Map headers) { + HttpURLConnection conn = null; + try { + conn = getHttpConnection(buildUrlQuery(url, queryParas), POST, headers); + conn.connect(); + + if (data != null) { + try (OutputStream out = conn.getOutputStream()) { + out.write(data.getBytes(CHARSET)); + out.flush(); + } + } + return readString(conn); + } catch (IOException e) { + LogFactory.getLog(HttpUtil.class).error("post error.", e); + return null; + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + if (conn != null) { + conn.disconnect(); + } + } + } + + public static String post(String url, Map queryParas, String data) { + return post(url, queryParas, data, null); + } + + public static String post(String url, String data, Map headers) { + return post(url, null, data, headers); + } + + public static String post(String url, String data) { + return post(url, null, data, null); + } + + private static String readString(HttpURLConnection conn) throws IOException { + try (InputStreamReader isr = new InputStreamReader(conn.getInputStream(), CHARSET)) { + StringBuilder ret = new StringBuilder(); + char[] buf = new char[1024]; + for (int num; (num = isr.read(buf, 0, buf.length)) != -1; ) { + ret.append(buf, 0, num); + } + return ret.toString(); + } + } + + + private static String buildUrlQuery(String url, Map queryParas) { + if (queryParas == null || queryParas.isEmpty()) { + return url; + } + + StringBuilder sb = new StringBuilder(url); + boolean isFirst; + if (url.indexOf('?') == -1) { + isFirst = true; + sb.append('?'); + } else { + isFirst = false; + } + + for (Entry entry : queryParas.entrySet()) { + if (isFirst) { + isFirst = false; + } else { + sb.append('&'); + } + + String key = entry.getKey(); + String value = entry.getValue(); + if (StringUtil.isNotBlank(value)) { + try { + value = URLEncoder.encode(value, CHARSET); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + sb.append(key).append('=').append(value); + } + return sb.toString(); + } + + +} + + + + + +