Browse Source

企业微信会话存储测试开发

anderx 7 months ago
parent
commit
6c60b68314

+ 15 - 0
pom.xml

@@ -468,6 +468,21 @@
 <!--			<artifactId>tess4j</artifactId>-->
 <!--			<version>5.8.0</version>-->
 <!--		</dependency>-->
+		<!--<dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <version>1.64</version>
+        </dependency>(这个好像可以不要)-->
+		<dependency>
+			<groupId>org.bouncycastle</groupId>
+			<artifactId>bcpg-jdk16</artifactId>
+			<version>1.46</version>
+		</dependency>
+		<dependency>
+			<groupId>org.bouncycastle</groupId>
+			<artifactId>bcpkix-jdk15on</artifactId>
+			<version>1.64</version>
+		</dependency>
 
 
 

+ 0 - 143
src/main/java/com/company/Main.java

@@ -1,143 +0,0 @@
-package com.company;
-
-import com.tencent.wework.Finance;
-
-import java.io.File;
-import java.io.FileOutputStream;
-
-//10000	参数错误,请求参数错误
-//10001	网络错误,网络请求错误
-//10002	数据解析失败
-//10003	系统失败
-//10004	密钥错误导致加密失败
-//10005	fileid错误
-//10006	解密失败
-//10007 找不到消息加密版本的私钥,需要重新传入私钥对
-//10008 解析encrypt_key出错
-//10009 ip非法
-//10010 数据过期
-
-public class Main {
-    public static void main(String[] args){
-
-        //seq 表示该企业存档消息序号,该序号单调递增,拉取序号建议设置为上次拉取返回结果中最大序号。首次拉取时seq传0,sdk会返回有效期内最早的消息。
-        //limit 表示本次拉取的最大消息条数,取值范围为1~1000
-        //proxy与passwd为代理参数,如果运行sdk的环境不能直接访问外网,需要配置代理参数。sdk访问的域名是"https://qyapi.weixin.qq.com"。
-        //建议先通过curl访问"https://qyapi.weixin.qq.com",验证代理配置正确后,再传入sdk。
-        //timeout 为拉取会话存档的超时时间,单位为秒,建议超时时间设置为5s。
-        //sdkfileid 媒体文件id,从解密后的会话存档中得到
-        //savefile 媒体文件保存路径
-        //encrypt_key 拉取会话存档返回的encrypt_random_key,使用配置在企业微信管理台的rsa公钥对应的私钥解密后得到encrypt_key。
-        //encrypt_chat_msg 拉取会话存档返回的encrypt_chat_msg
-//        if (args.length < 2) {
-//            System.out.println("./sdktools 1(chatmsg) 2(mediadata) 3(decryptdata)\n");
-//            System.out.println("./sdktools 1 seq limit proxy passwd timeout\n");
-//            System.out.println("./sdktools 2 fileid proxy passwd timeout savefile\n");
-//            System.out.println("./sdktools 3 encrypt_key encrypt_chat_msg\n");
-//            return;
-//        }
-
-        long ret = 0;
-        //使用sdk前需要初始化,初始化成功后的sdk可以一直使用。
-        //如需并发调用sdk,建议每个线程持有一个sdk实例。
-        //初始化时请填入自己企业的corpid与secrectkey。
-        long sdk = Finance.NewSdk();
-        ret = Finance.Init(sdk, "wwd1f2fb82952be74c", "0k4XYuHUl4QB8QTB6cAOSaRIX00ur1Vyjjz4p_REP_k");
-        System.out.println(ret);
-        String arg0 = "0";
-        if(ret != 0){
-            Finance.DestroySdk(sdk);
-            System.out.println("init sdk err ret " + ret);
-            return;
-        }else {
-            System.out.println("init sdk ok");
-        }
-        if (arg0.equals("1")) {
-            //拉取会话存档
-            int seq = Integer.parseInt(args[1]);
-            int limit = Integer.parseInt(args[2]);
-            String proxy = args[3];
-            String passwd = args[4];
-            int timeout = Integer.parseInt(args[5]);
-
-            //每次使用GetChatData拉取存档前需要调用NewSlice获取一个slice,在使用完slice中数据后,还需要调用FreeSlice释放。
-            long slice = Finance.NewSlice();
-            ret = Finance.GetChatData(sdk, seq, limit, proxy, passwd, timeout, slice);
-            System.out.println("==============="+ret);
-            if (ret != 0) {
-                System.out.println("getchatdata ret " + ret);
-                Finance.FreeSlice(slice);
-                return;
-            }
-            System.out.println("getchatdata :" + Finance.GetContentFromSlice(slice));
-            Finance.FreeSlice(slice);
-        }
-        else if (args[0].equals("2")) {
-            //拉取媒体文件
-            String sdkfileid = args[1];
-            String proxy = args[2];
-            String passwd = args[3];
-            int timeout = Integer.parseInt(args[4]);
-            String savefile = args[5];
-
-            //媒体文件每次拉取的最大size为512k,因此超过512k的文件需要分片拉取。若该文件未拉取完整,sdk的IsMediaDataFinish接口会返回0,同时通过GetOutIndexBuf接口返回下次拉取需要传入GetMediaData的indexbuf。
-            //indexbuf一般格式如右侧所示,”Range:bytes=524288-1048575“,表示这次拉取的是从524288到1048575的分片。单个文件首次拉取填写的indexbuf为空字符串,拉取后续分片时直接填入上次返回的indexbuf即可。
-            String indexbuf = "";
-            while(true){
-                //每次使用GetMediaData拉取存档前需要调用NewMediaData获取一个media_data,在使用完media_data中数据后,还需要调用FreeMediaData释放。
-                long media_data = Finance.NewMediaData();
-                ret = Finance.GetMediaData(sdk, indexbuf, sdkfileid, proxy, passwd, timeout, media_data);
-                if(ret!=0){
-                    System.out.println("getmediadata ret:" + ret);
-                    Finance.FreeMediaData(media_data);
-                    return;
-                }
-                System.out.printf("getmediadata outindex len:%d, data_len:%d, is_finis:%d\n",Finance.GetIndexLen(media_data),Finance.GetDataLen(media_data), Finance.IsMediaDataFinish(media_data));
-                try {
-                    //大于512k的文件会分片拉取,此处需要使用追加写,避免后面的分片覆盖之前的数据。
-                    FileOutputStream outputStream  = new FileOutputStream(new File(savefile), true);
-                    outputStream.write(Finance.GetData(media_data));
-                    outputStream.close();
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-
-                if(Finance.IsMediaDataFinish(media_data) == 1)
-                {
-                    //已经拉取完成最后一个分片
-                    Finance.FreeMediaData(media_data);
-                    break;
-                }
-                else
-                {
-                    //获取下次拉取需要使用的indexbuf
-                    indexbuf = Finance.GetOutIndexBuf(media_data);
-                    Finance.FreeMediaData(media_data);
-                }
-            }
-        }
-        else if (args[0].equals("3")) {
-            //解密会话存档内容
-            //sdk不会要求用户传入rsa私钥,保证用户会话存档数据只有自己能够解密。
-            //此处需要用户先用rsa私钥解密encrypt_random_key后,作为encrypt_key参数传入sdk来解密encrypt_chat_msg获取会话存档明文。
-            String encrypt_key = args[1];
-            String encrypt_chat_msg = args[2];
-
-            //每次使用DecryptData解密会话存档前需要调用NewSlice获取一个slice,在使用完slice中数据后,还需要调用FreeSlice释放。
-            long msg = Finance.NewSlice();
-            ret = Finance.DecryptData(sdk, encrypt_key, encrypt_chat_msg, msg);
-            if (ret != 0) {
-                System.out.println("getchatdata ret " + ret);
-                Finance.FreeSlice(msg);
-                return;
-            }
-            System.out.println("decrypt ret:" + ret + " msg:" + Finance.GetContentFromSlice(msg));
-            Finance.FreeSlice(msg);
-        }
-        else {
-            System.out.println("wrong args " + args[0]);
-        }
-        Finance.DestroySdk(sdk);
-    }
-}
-

+ 0 - 55
src/main/java/com/goafanti/common/utils/weChat/ConversationContentUtils.java

@@ -1,55 +0,0 @@
-package com.goafanti.common.utils.weChat;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
-@Component
-public class ConversationContentUtils {
-
-    @Value(value = "${conversationContent.corpid}")
-    private String corpid;
-    @Value(value = "${conversationContent.secret}")
-    private String secret;
-
-    public void getConversationContent() {
-        long sdk = Finance.NewSdk();
-        System.out.println(Finance.Init(sdk, corpid, secret));
-
-
-        long ret = 0;
-        int seq = 0;
-        int limit =20;
-        long slice = Finance.NewSlice();
-        ret = Finance.GetChatData(sdk, seq, limit,null, null, 3, slice);
-        if (ret != 0) {
-            System.out.println("getchatdata ret " + ret);
-            return;
-        }
-        String getchatdata = Finance.GetContentFromSlice(slice);
-        JSONObject jo = new JSONObject(getchatdata);
-        JSONArray chatdata = jo.getJSONArray("chatdata");
-        System.out.println("消息数:" + chatdata.length());
-        for (int i = 0; i < chatdata.length(); i++) {
-            String item = chatdata.get(i).toString();
-            JSONObject data = new JSONObject(item);
-            String encrypt_random_key = data.getString("encrypt_random_key");
-            String encrypt_chat_msg = data.getString("encrypt_chat_msg");
-            long msg = Finance.NewSlice();
-            try {
-                String message = RSAEncrypt.decryptRSA(encrypt_random_key,priKey);
-                ret = Finance.DecryptData(sdk, message, encrypt_chat_msg, msg);
-                if (ret != 0) {
-                    System.out.println("getchatdata ret " + ret);
-                    return;
-                }
-                System.out.println("decrypt ret:" + ret + " msg:" + Finance.GetContentFromSlice(msg));
-                Finance.FreeSlice(msg);
-                System.out.println(message);
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-
-        }
-        Finance.FreeSlice(slice);
-    }
-}

+ 37 - 21
src/main/java/com/goafanti/common/utils/weChat/Finance.java

@@ -22,9 +22,9 @@ public class Finance {
      * 初始化函数
      * Return值=0表示该API调用成功
      *
-     * @param [in]  sdk			NewSdk返回的sdk指针
-     * @param [in]  corpid      调用企业的企业id,例如:wwd08c8exxxx5ab44d,可以在企业微信管理端--我的企业--企业信息查看
-     * @param [in]  secret		聊天内容存档的Secret,可以在企业微信管理端--管理工具--聊天内容存档查看
+     * @param   sdk			NewSdk返回的sdk指针
+     * @param   corpid      调用企业的企业id,例如:wwd08c8exxxx5ab44d,可以在企业微信管理端--我的企业--企业信息查看
+     * @param   secret		聊天内容存档的Secret,可以在企业微信管理端--管理工具--聊天内容存档查看
      *
      *
      * @return 返回是否初始化成功
@@ -38,14 +38,12 @@ public class Finance {
      * Return值=0表示该API调用成功
      *
      *
-     * @param [in]  sdk				NewSdk返回的sdk指针
-     * @param [in]  seq				从指定的seq开始拉取消息,注意的是返回的消息从seq+1开始返回,seq为之前接口返回的最大seq值。首次使用请使用seq:0
-     * @param [in]  limit			一次拉取的消息条数,最大值1000条,超过1000条会返回错误
-     * @param [in]  proxy			使用代理的请求,需要传入代理的链接。如:socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081
-     * @param [in]  passwd			代理账号密码,需要传入代理的账号密码。如 user_name:passwd_123
-     * @param [out] chatDatas		返回本次拉取消息的数据,slice结构体.内容包括errcode/errmsg,以及每条消息内容。
-
-
+     * @param   sdk				NewSdk返回的sdk指针
+     * @param   seq				从指定的seq开始拉取消息,注意的是返回的消息从seq+1开始返回,seq为之前接口返回的最大seq值。首次使用请使用seq:0
+     * @param   limit			一次拉取的消息条数,最大值1000条,超过1000条会返回错误
+     * @param   proxy			使用代理的请求,需要传入代理的链接。如:socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081
+     * @param   passwd			代理账号密码,需要传入代理的账号密码。如 user_name:passwd_123
+     * @param  chatDatas		返回本次拉取消息的数据,slice结构体.内容包括errcode/errmsg,以及每条消息内容。
      *
      * @return 返回是否调用成功
      *      0   - 成功
@@ -58,11 +56,11 @@ public class Finance {
      * Return值=0表示该API调用成功
      *
      *
-     * @param [in]  sdk				NewSdk返回的sdk指针
-     * @param [in]  sdkFileid		从GetChatData返回的聊天消息中,媒体消息包括的sdkfileid
-     * @param [in]  proxy			使用代理的请求,需要传入代理的链接。如:socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081
-     * @param [in]  passwd			代理账号密码,需要传入代理的账号密码。如 user_name:passwd_123
-     * @param [in]  indexbuf		媒体消息分片拉取,需要填入每次拉取的索引信息。首次不需要填写,默认拉取512k,后续每次调用只需要将上次调用返回的outindexbuf填入即可。
+     * @param   sdk				NewSdk返回的sdk指针
+     * @param   sdkFileid		从GetChatData返回的聊天消息中,媒体消息包括的sdkfileid
+     * @param   proxy			使用代理的请求,需要传入代理的链接。如:socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081
+     * @param   passwd			代理账号密码,需要传入代理的账号密码。如 user_name:passwd_123
+     * @param   indexbuf		媒体消息分片拉取,需要填入每次拉取的索引信息。首次不需要填写,默认拉取512k,后续每次调用只需要将上次调用返回的outindexbuf填入即可。
      * @param [out] media_data		返回本次拉取的媒体数据.MediaData结构体.内容包括data(数据内容)/outindexbuf(下次索引)/is_finish(拉取完成标记)
 
      *
@@ -74,8 +72,8 @@ public class Finance {
 
     /**
      * @brief 解析密文
-     * @param [in]  encrypt_key, getchatdata返回的encrypt_key
-     * @param [in]  encrypt_msg, getchatdata返回的content
+     * @param   encrypt_key, getchatdata返回的encrypt_key
+     * @param   encrypt_msg, getchatdata返回的content
      * @param [out] msg, 解密的消息明文
      * @return 返回是否调用成功
      *      0   - 成功
@@ -125,8 +123,26 @@ public class Finance {
     public native static int IsMediaDataFinish(long mediaData);
 
     static {
-        String path = Finance.class.getResource("").getPath();
-        System.load(path.concat("libWeWorkFinanceSdk_Java.so"));
-        System.loadLibrary("WeWorkFinanceSdk_Java");
+        if (isWindows()) {
+//            String path = Finance.class.getResource("").getPath().replaceAll("%20", " ").replaceFirst("/", "").replace("/", "\\\\");
+            //定位到resources目录
+            String path = "C:\\gitProject\\kede-server\\src\\main\\resources\\sdk\\";
+            System.out.println(path.concat("libcrypto-3-x64.dll"));
+            System.load(path.concat("libcrypto-3-x64.dll"));
+            System.load(path.concat("libcurl-x64.dll"));
+            System.load(path.concat("WeWorkFinanceSdk.dll"));
+        } else {
+            String path = "/usr/local/tomcat-kede/webapps/test/WEB-INF/classes/sdk/libWeWorkFinanceSdk_Java.so";
+            System.out.println(path);
+            System.load(path);
+        }
+//        System.loadLibrary("WeWorkFinanceSdk_Java");
     }
+
+    public static boolean isWindows() {
+        String osName = System.getProperties().getProperty("os.name");
+        System.out.println("current system is " + osName);
+        return osName.toUpperCase().indexOf("WINDOWS") != -1;
+    }
+
 }

+ 34 - 22
src/main/java/com/goafanti/common/utils/weChat/RSAEncrypt.java

@@ -1,27 +1,39 @@
 package com.goafanti.common.utils.weChat;
 
+import org.apache.commons.codec.binary.Base64;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+
+import javax.crypto.Cipher;
+import java.io.Reader;
+import java.io.StringReader;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.Security;
+
 public class RSAEncrypt {
-//
-//    public static String decryptRSA(String str, String privateKey) throws Exception {
-//        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
-//        Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
-//        rsa.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKey));
-//        byte[] utf8 = rsa.doFinal(Base64.decodeBase64(str));
-//        String result = new String(utf8,"UTF-8");
-//        return result;
-//    }
-//
-//    public static Key getPrivateKey (String privateKey) throws Exception {
-//        Reader privateKeyReader = new StringReader(privateKey);
-//        PEMParser privatePemParser = new PEMParser(privateKeyReader);
-//        Object privateObject = privatePemParser.readObject();
-//        if (privateObject instanceof PEMKeyPair) {
-//            PEMKeyPair pemKeyPair = (PEMKeyPair) privateObject;
-//            JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
-//            PrivateKey privKey = converter.getPrivateKey(pemKeyPair.getPrivateKeyInfo());
-//            return privKey;
-//        }
-//        return null;
-//    }
+
+    public static String decryptRSA(String str, String privateKey) throws Exception {
+        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+        Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
+        rsa.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKey));
+        byte[] utf8 = rsa.doFinal(Base64.decodeBase64(str));
+        String result = new String(utf8,"UTF-8");
+        return result;
+    }
+
+    public static Key getPrivateKey (String privateKey) throws Exception {
+        Reader privateKeyReader = new StringReader(privateKey);
+        PEMParser privatePemParser = new PEMParser(privateKeyReader);
+        Object privateObject = privatePemParser.readObject();
+        if (privateObject instanceof PEMKeyPair) {
+            PEMKeyPair pemKeyPair = (PEMKeyPair) privateObject;
+            JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
+            PrivateKey privKey = converter.getPrivateKey(pemKeyPair.getPrivateKeyInfo());
+            return privKey;
+        }
+        return null;
+    }
 
 }

+ 4 - 0
src/main/java/com/goafanti/weChat/controller/ConversationContentController.java

@@ -15,6 +15,10 @@ public class ConversationContentController extends CertifyApiController {
     @Resource
     private ConversationContentService conversationContentService;
 
+    /**
+     * 获取会话内容
+     * @return
+     */
     @GetMapping(value = "/getChatData")
     public String getChatData()
     {

+ 2 - 0
src/main/resources/props/config_local.properties

@@ -30,6 +30,8 @@ jdbc.removeAbandonedTimeout=300
 jdbc.logAbandoned=true
 jdbc.filters=stat
 logging.level.com.goafanti=DEBUG
+conversationContent.corpid=wwd1f2fb82952be74c
+conversationContent.secret=0k4XYuHUl4QB8QTB6cAOSaRIX00ur1Vyjjz4p_REP_k
 
 jedis.host=localhost
 jedis.port=6379

BIN
src/main/resources/sdk/WeWorkFinanceSdk.dll


src/main/java/com/goafanti/common/utils/weChat/libWeWorkFinanceSdk_Java.so → src/main/resources/sdk/libWeWorkFinanceSdk_Java.so


BIN
src/main/resources/sdk/libcrypto-3-x64.dll


BIN
src/main/resources/sdk/libcurl-x64.dll