Commit ec21c8e3 authored by 黎博's avatar 黎博

删除mock模块,相应功能已经迁移到holems服务

parent d8e6304a
package cn.qg.qaplatform.mock.config;
import cn.qg.qaplatform.mock.interceptor.YeebaoInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Bean
public YeebaoInterceptor yeebaoInterceptor() {
return new YeebaoInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(yeebaoInterceptor()).addPathPatterns("/mock/tzt-api/**", "/mock/balance-board/**");
}
}
package cn.qg.qaplatform.mock.controller;
import cn.qg.qaplatform.config.SwitchDataSource;
import cn.qg.qaplatform.mock.entity.Mock;
import cn.qg.qaplatform.mock.service.MockService;
import cn.qg.qaplatform.utils.JsonResult;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@CrossOrigin
@RestController
public class MockController {
@Autowired
MockService mockService;
@RequestMapping(value = "/mock/**", method = { RequestMethod.GET, RequestMethod.POST})
public void mockMethod() {}
@PostMapping("/add/mock")
public JsonResult addMock(@RequestBody Mock mock) {
SwitchDataSource.dataSourceSwitch("pre", "qa");
return JsonResult.success(mockService.save(mock));
}
@GetMapping("/list/mock")
public JsonResult getMockList(Integer pageNum, Integer pageSize) {
SwitchDataSource.dataSourceSwitch("pre", "qa");
IPage<Mock> page = new Page<>(pageNum, pageSize);
IPage<Mock> pageEntity = mockService.page(page);
Map<String, Object> map = new HashMap<>();
map.put("list", pageEntity.getRecords());
map.put("total", pageEntity.getTotal());
return JsonResult.success(map);
}
@PostMapping("/edit/mock")
public JsonResult modifyMock(@RequestBody Mock mock) {
SwitchDataSource.dataSourceSwitch("pre", "qa");
return JsonResult.success(mockService.saveOrUpdate(mock));
}
@PostMapping(value = "/mock/test", consumes = "application/xml")
public String balanceboardTransfer(@RequestBody String requestData) {
String cmd = requestData.toString().split("<cmd>")[1].split("</cmd>")[0];
log.info("Mock controller yeepay-transfer cmd-------- {}", cmd);
String transferResponse = null;
if("AccountBalanaceQuery".equals(cmd)){
//查询余额的返回值
transferResponse = "<data><cmd>AccountBalanaceQuery</cmd><hmac>MIIE6QYJKoZIhvcNAQcCoIIE2jCCBNYCAQExCzAJBgUrDgMCGgUAMC8GCSqGSIb3DQEHAaAiBCAxYTcyYmQwZWVmMWIyNDRkNTFlNmEzYTAwMjk1Mjk1OKCCA7EwggOtMIIDFqADAgECAhAuyfCgPbMcigfvVyGazeQRMA0GCSqGSIb3DQEBBQUAMCQxCzAJBgNVBAYTAkNOMRUwEwYDVQQKEwxDRkNBIFRFU1QgQ0EwHhcNMTExMTI4MDcwOTUzWhcNMTMxMTI4MDcwOTUzWjBzMQswCQYDVQQGEwJDTjEVMBMGA1UEChMMQ0ZDQSBURVNUIENBMQ8wDQYDVQQLEwZZRUVQQVkxEjAQBgNVBAsTCUN1c3RvbWVyczEoMCYGA1UEAxQfMDQxQFoxMjNxd2VAemhpd2VuLm1laUAwMDAwMDAwMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzrITNElBaFF7xPXtPguWeTnGOI1gVMMkUDI57ZQz+Gg9PPcfF+ExrtDgMQEOwfRs7X4XiraPE2l6ub0Xkpl0ftu8ELnii91wUKAqsvp88NIdAdLQnC7PeveWlquVSAf//2WtAkdBI7xnhXaL/ObUkhHheT0aR5miYmDyLAkTBj8CAwEAAaOCAY8wggGLMB8GA1UdIwQYMBaAFEZy3CVynwJOVYO1gPkL2+mTs/RFMB0GA1UdDgQWBBS0k6A7ZSwLRwbIhFsgcChrYd27PDALBgNVHQ8EBAMCBaAwDAYDVR0TBAUwAwEBADA7BgNVHSUENDAyBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgwgfAGA1UdHwSB6DCB5TBPoE2gS6RJMEcxCzAJBgNVBAYTAkNOMRUwEwYDVQQKEwxDRkNBIFRFU1QgQ0ExDDAKBgNVBAsTA0NSTDETMBEGA1UEAxMKY3JsMTI2XzE5NDCBkaCBjqCBi4aBiGxkYXA6Ly90ZXN0bGRhcC5jZmNhLmNvbS5jbjozODkvQ049Y3JsMTI2XzE5NCxPVT1DUkwsTz1DRkNBIFRFU1QgQ0EsQz1DTj9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Y2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwDQYJKoZIhvcNAQEFBQADgYEAKX4CXCPQEE4RWGsZTXZXLBct2gcPYEjqpgPZ5ERiUrYLTDGuIT90ECfSoxCrcTJEeY7EJBojig9gLRoMn/4xXW/XscGarQ3XxyZw8VxTMFkotuUkAPoaacYlIrc34t2DR0DqvU6umgFL3yTMYxl5WLjOh47OH7Aw7VPscmrtzEIxgd0wgdoCAQEwODAkMQswCQYDVQQGEwJDTjEVMBMGA1UEChMMQ0ZDQSBURVNUIENBAhAuyfCgPbMcigfvVyGazeQRMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYBW4+qU8lVs4gEk/o+ln33umTlBDViDf+VMA/6vDhfECTy1fbBHqqr84QFBagMqEXGHzXzzP8qGRRAhmKLhn4RimcrvRh3BRbcQig6OEL/Zz1SphFEH0+BRAN+jhLYRt7+zQZvBx65rE52ivMqCpmEQ+6F4BbNCWwJ+0/xbCE4m5Q==</hmac><ret_Code>1</ret_Code><balance_Amount>291227.76</balance_Amount><valid_Amount>291227.76</valid_Amount></data>";
}else if("TransferBatch".equals(cmd)){
String batchNo = requestData.toString().split("<batch_No>")[1].split("</batch_No>")[0];
//申请易宝放款的返回值
transferResponse = "<?xml version='1.0' encoding='GBK'?><data><cmd>TransferBatch</cmd><hmac>MIIE6QYJKoZIhvcNAQcCoIIE2jCCBNYCAQExCzAJBgUrDgMCGgUAMC8GCSqGSIb3DQEHAaAiBCAyYjM0NGJiNmVlZDliYmY1Mjk3MGNkMGFjMjNlMTA5NqCCA7EwggOtMIIDFqADAgECAhAuyfCgPbMcigfvVyGazeQRMA0GCSqGSIb3DQEBBQUAMCQxCzAJBgNVBAYTAkNOMRUwEwYDVQQKEwxDRkNBIFRFU1QgQ0EwHhcNMTExMTI4MDcwOTUzWhcNMTMxMTI4MDcwOTUzWjBzMQswCQYDVQQGEwJDTjEVMBMGA1UEChMMQ0ZDQSBURVNUIENBMQ8wDQYDVQQLEwZZRUVQQVkxEjAQBgNVBAsTCUN1c3RvbWVyczEoMCYGA1UEAxQfMDQxQFoxMjNxd2VAemhpd2VuLm1laUAwMDAwMDAwMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzrITNElBaFF7xPXtPguWeTnGOI1gVMMkUDI57ZQz+Gg9PPcfF+ExrtDgMQEOwfRs7X4XiraPE2l6ub0Xkpl0ftu8ELnii91wUKAqsvp88NIdAdLQnC7PeveWlquVSAf//2WtAkdBI7xnhXaL/ObUkhHheT0aR5miYmDyLAkTBj8CAwEAAaOCAY8wggGLMB8GA1UdIwQYMBaAFEZy3CVynwJOVYO1gPkL2+mTs/RFMB0GA1UdDgQWBBS0k6A7ZSwLRwbIhFsgcChrYd27PDALBgNVHQ8EBAMCBaAwDAYDVR0TBAUwAwEBADA7BgNVHSUENDAyBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgwgfAGA1UdHwSB6DCB5TBPoE2gS6RJMEcxCzAJBgNVBAYTAkNOMRUwEwYDVQQKEwxDRkNBIFRFU1QgQ0ExDDAKBgNVBAsTA0NSTDETMBEGA1UEAxMKY3JsMTI2XzE5NDCBkaCBjqCBi4aBiGxkYXA6Ly90ZXN0bGRhcC5jZmNhLmNvbS5jbjozODkvQ049Y3JsMTI2XzE5NCxPVT1DUkwsTz1DRkNBIFRFU1QgQ0EsQz1DTj9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Y2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwDQYJKoZIhvcNAQEFBQADgYEAKX4CXCPQEE4RWGsZTXZXLBct2gcPYEjqpgPZ5ERiUrYLTDGuIT90ECfSoxCrcTJEeY7EJBojig9gLRoMn/4xXW/XscGarQ3XxyZw8VxTMFkotuUkAPoaacYlIrc34t2DR0DqvU6umgFL3yTMYxl5WLjOh47OH7Aw7VPscmrtzEIxgd0wgdoCAQEwODAkMQswCQYDVQQGEwJDTjEVMBMGA1UEChMMQ0ZDQSBURVNUIENBAhAuyfCgPbMcigfvVyGazeQRMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYAC38fZ2TRB7Myf2VWcQSmGMCO2lGcuAtUfA2m9pHiZ1CZ/cUd/Jj1bmN94QT+7IcPOXw2ZPBbCufeClYHSZRLy3hk3P+WhpGQenlp5zTkJjGvKFKxOdDp6ymlruCE/wQRwH9rMrxhuLkyEauAOQEAeE8EtBsKtBhVanSxEWYlSug==</hmac><ret_Code>1</ret_Code><mer_Id>10000449592</mer_Id><batch_No>" + batchNo + "</batch_No><total_Amt>0.01</total_Amt><total_Num>1</total_Num><r1_Code>0025</r1_Code></data>";
}else if("BatchDetailQuery".equals(cmd)){
String batchNo = requestData.toString().split("<batch_No>")[1].split("</batch_No>")[0];
//放款结果查询的返回值
transferResponse = "<data><cmd>BatchDetailQuery</cmd><hmac>MIIE6QYJKoZIhvcNAQcCoIIE2jCCBNYCAQExCzAJBgUrDgMCGgUAMC8GCSqGSIb3DQEHAaAiBCA2ZWU1ODE3Y2UwNDg4NDczNmJlNWFlNGM0MDViZGNlYaCCA7EwggOtMIIDFqADAgECAhAuyfCgPbMcigfvVyGazeQRMA0GCSqGSIb3DQEBBQUAMCQxCzAJBgNVBAYTAkNOMRUwEwYDVQQKEwxDRkNBIFRFU1QgQ0EwHhcNMTExMTI4MDcwOTUzWhcNMTMxMTI4MDcwOTUzWjBzMQswCQYDVQQGEwJDTjEVMBMGA1UEChMMQ0ZDQSBURVNUIENBMQ8wDQYDVQQLEwZZRUVQQVkxEjAQBgNVBAsTCUN1c3RvbWVyczEoMCYGA1UEAxQfMDQxQFoxMjNxd2VAemhpd2VuLm1laUAwMDAwMDAwMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzrITNElBaFF7xPXtPguWeTnGOI1gVMMkUDI57ZQz+Gg9PPcfF+ExrtDgMQEOwfRs7X4XiraPE2l6ub0Xkpl0ftu8ELnii91wUKAqsvp88NIdAdLQnC7PeveWlquVSAf//2WtAkdBI7xnhXaL/ObUkhHheT0aR5miYmDyLAkTBj8CAwEAAaOCAY8wggGLMB8GA1UdIwQYMBaAFEZy3CVynwJOVYO1gPkL2+mTs/RFMB0GA1UdDgQWBBS0k6A7ZSwLRwbIhFsgcChrYd27PDALBgNVHQ8EBAMCBaAwDAYDVR0TBAUwAwEBADA7BgNVHSUENDAyBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgwgfAGA1UdHwSB6DCB5TBPoE2gS6RJMEcxCzAJBgNVBAYTAkNOMRUwEwYDVQQKEwxDRkNBIFRFU1QgQ0ExDDAKBgNVBAsTA0NSTDETMBEGA1UEAxMKY3JsMTI2XzE5NDCBkaCBjqCBi4aBiGxkYXA6Ly90ZXN0bGRhcC5jZmNhLmNvbS5jbjozODkvQ049Y3JsMTI2XzE5NCxPVT1DUkwsTz1DRkNBIFRFU1QgQ0EsQz1DTj9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Y2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwDQYJKoZIhvcNAQEFBQADgYEAKX4CXCPQEE4RWGsZTXZXLBct2gcPYEjqpgPZ5ERiUrYLTDGuIT90ECfSoxCrcTJEeY7EJBojig9gLRoMn/4xXW/XscGarQ3XxyZw8VxTMFkotuUkAPoaacYlIrc34t2DR0DqvU6umgFL3yTMYxl5WLjOh47OH7Aw7VPscmrtzEIxgd0wgdoCAQEwODAkMQswCQYDVQQGEwJDTjEVMBMGA1UEChMMQ0ZDQSBURVNUIENBAhAuyfCgPbMcigfvVyGazeQRMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYCD/g83n6KyattYAEPqff/9z613+4AaZDHVxY9xEb3lBGRRosVQptgkZItEc9cM2Em/o9GfV/mqj5T6CP5glvbbtFnrz2Z0GGNbDR/gqOIPhpACRZozZipwUeQESVhRCiCJa4sPuoEkgSSq5XvL5nIvAxc59DeKWIv/LGqYq9dK8Q==</hmac><ret_Code>1</ret_Code><batch_No>' + batchNo + '</batch_No><total_Num>1</total_Num><end_Flag>Y</end_Flag><list><items><item><remarksInfo></remarksInfo><amount>0.01</amount><fee></fee><abstractInfo>提现打款</abstractInfo><note/><order_Id>PAYMENT78162155286528</order_Id><payee_Bank_Account>1506213009022200623</payee_Bank_Account><refund_Date></refund_Date><real_pay_amount>0.01</real_pay_amount><payee_BankName>工商银行</payee_BankName><complete_Date>2020-01-16 18:20:09</complete_Date><request_Date>2020-01-16 18:20:08</request_Date><payee_Name>蒋素霞</payee_Name><bank_Status>S</bank_Status><r1_Code>0026</r1_Code><fail_Desc></fail_Desc></item></items></list></data>";
}
return transferResponse;
}
}
package cn.qg.qaplatform.mock.encrypt.factory;
public interface EncryptConvertor {
String encrypt(String response);
String decrypt(String request);
}
package cn.qg.qaplatform.mock.encrypt.factory;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class EncryptFactory {
public static EncryptConvertor produce(String type) {
if ("yeebao".equals(type)) {
return new YeebaoEncryptConvertor();
} else {
log.info("请输入正确的加密类型类型!");
return null;
}
}
}
package cn.qg.qaplatform.mock.encrypt.factory;
import cn.qg.qaplatform.mock.encrypt.paycenter.Aes;
import cn.qg.qaplatform.mock.encrypt.paycenter.Rsa;
import cn.qg.qaplatform.utils.JsonTransUtils;
import java.util.HashMap;
import java.util.Map;
public class YeebaoEncryptConvertor implements EncryptConvertor {
private final String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANSBQSc0Hlr+mS7uoIjYS71X2DJ6ZrCcbB1uICqty9QY6W16nZ8tLN/d9k2Z+e2rGG8s7PskpU2T+WuJeDSXs/vpPllG8/tSRVaWcr9EzPaSti3ltSUH0QOLSypZEjTT/slscExj4PMOmQXUXP3gewjNWz1cYRI7dGnKPm+ZFah/AgMBAAECgYB8AcFngz6DkzcI8C+2K6JnJ6/+JPdv8JgWxID45tqfNrphLMB2dwJM0VY+CrCSRNnJZsoT9FqSXtuaKWqAJlbchhPZjupA9RkWFzlGpCQ63/CC71RYYY03eCnc7AIpn52whkjfWG/yf57jKzEwUT+U034uvXdaA+lVvJ0xqpj3gQJBAOmLODjecn450TJbNQaop+7Q5Hz2TUIxbYakzPpcLGv1QYgHa657r7PJ23ZltDBGldMaNTZfqJrtDcq0rTA4lBECQQDo8CcdUhMZ3JbR2UZN0CG8ljMbNWgNWBa37ebE3ZG5yYldc7zY9US/+/7lhxNDqG0saTvM9pJwEc3ccVMvksOPAkEAqq7V+zIQKVJmItBn06MFgNNoei+kTUFEk8f0CvG8gXYwW5NYzp+UzOg1HbW82B9uNmeMBl4pInknwEMF5B0lkQJAdRxQPgCGk+kAdo6LNxHd9Ed7eEF4h8Ty3xQfgnh3DHYTtsU6e8WMBA24kENB3zEtejeKFjkdVHTPD/Z1wSRDZwJAAvNuq0YuRDsESOAerkBZKonA5CD0M4vHTRqihHrjBohv6yxBU8P7gALrX7qmoaZ3aLmN8wHdOAGTR6LZjQdkoQ==";
private String aesKey = null;
private String encryptKey = null;
/**
* 易宝加密
* @param response
* @return
*/
@Override
public String encrypt(String response) {
try {
Map responseMap = JsonTransUtils.strToMap(response);
Map<String, Object> signData = new HashMap<>();
responseMap.put("sign", Rsa.sign(response, privateKey));
signData.put("encryptkey", encryptKey);
signData.put("data", Aes.encryptToBase64(JsonTransUtils.mapToJson(responseMap), aesKey));
return JsonTransUtils.mapToJson(signData);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 易宝解密
* @param request Http请求的request
* @return
*/
@Override
public String decrypt(String request) {
try {
Map requestMap = JsonTransUtils.strToMap(request);
encryptKey = requestMap.get("encryptkey").toString();
aesKey = Rsa.decrypt(encryptKey, privateKey);
return Aes.decryptFromBase64((String) requestMap.get("data"), aesKey);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
package cn.qg.qaplatform.mock.encrypt.paycenter;
public abstract class AbstractConvertUtils {
private AbstractConvertUtils() {
}
public static String toHex(byte input[]) {
if (input == null) {
return null;
}
StringBuffer output = new StringBuffer(input.length * 2);
for (int i = 0; i < input.length; i++) {
int current = input[i] & 0xff;
if (current < 16) {
output.append("0");
}
output.append(Integer.toString(current, 16));
}
return output.toString();
}
}
package cn.qg.qaplatform.mock.encrypt.paycenter;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class Aes {
private static final int KEY_LENGTH = 16;
/**
* 加密
*
* @param data 需要加密的内容
* @param key 加密密码
*/
public static byte[] encrypt(byte[] data, byte[] key) {
CheckUtils.notEmpty(data, "data");
CheckUtils.notEmpty(key, "key");
if (key.length != KEY_LENGTH) {
throw new RuntimeException("Invalid Aes key length (must be 16 bytes)");
}
try {
SecretKeySpec secretKey = new SecretKeySpec(key, "Aes");
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "Aes");
Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.AES_ALGORITHM);// 创建密码器
cipher.init(Cipher.ENCRYPT_MODE, seckey);// 初始化
byte[] result = cipher.doFinal(data);
return result; // 加密
} catch (Exception e) {
throw new RuntimeException("encrypt fail!", e);
}
}
/**
* 解密
*
* @param data 待解密内容
* @param key 解密密钥
*/
public static byte[] decrypt(byte[] data, byte[] key) {
CheckUtils.notEmpty(data, "data");
CheckUtils.notEmpty(key, "key");
if (key.length != KEY_LENGTH) {
throw new RuntimeException("Invalid Aes key length (must be 16 bytes)");
}
try {
SecretKeySpec secretKey = new SecretKeySpec(key, "Aes");
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "Aes");
Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.AES_ALGORITHM);// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, seckey);// 初始化
byte[] result = cipher.doFinal(data);
return result; // 加密
} catch (Exception e) {
throw new RuntimeException("decrypt fail!", e);
}
}
public static String encryptToBase64(String data, String key) {
try {
byte[] valueByte = encrypt(data.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING),
key.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING));
return new String(Base64.encode(valueByte));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("encrypt fail!", e);
}
}
public static String decryptFromBase64(String data, String key) {
try {
byte[] originalData = Base64.decode(data.getBytes());
byte[] valueByte =
decrypt(originalData, key.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING));
return new String(valueByte, ConfigureEncryptAndDecrypt.CHAR_ENCODING);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("decrypt fail!", e);
}
}
public static String encryptWithKeyBase64(String data, String key) {
try {
byte[] valueByte = encrypt(data.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING),
Base64.decode(key.getBytes()));
return new String(Base64.encode(valueByte));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("encrypt fail!", e);
}
}
public static String decryptWithKeyBase64(String data, String key) {
try {
byte[] originalData = Base64.decode(data.getBytes());
byte[] valueByte = decrypt(originalData, Base64.decode(key.getBytes()));
return new String(valueByte, ConfigureEncryptAndDecrypt.CHAR_ENCODING);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("decrypt fail!", e);
}
}
public static byte[] genarateRandomKey() {
KeyGenerator keygen = null;
try {
keygen = KeyGenerator.getInstance(ConfigureEncryptAndDecrypt.AES_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(" genarateRandomKey fail!", e);
}
SecureRandom random = new SecureRandom();
keygen.init(random);
Key key = keygen.generateKey();
return key.getEncoded();
}
public static String genarateRandomKeyWithBase64() {
return new String(Base64.encode(genarateRandomKey()));
}
}
package cn.qg.qaplatform.mock.encrypt.paycenter;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;
public class CheckUtils {
/**
* 验证对象是否为NULL,空字符串,空数组,空的Collection或Map(只有空格的字符串也认为是空串)
*
* @param obj 被验证的对象
* @param message 异常信息
*/
@SuppressWarnings("rawtypes")
public static void notEmpty(Object obj, String message) {
if (obj == null) {
throw new IllegalArgumentException(message + " must be specified");
}
if (obj instanceof String && obj.toString().trim().length() == 0) {
throw new IllegalArgumentException(message + " must be specified");
}
if (obj.getClass().isArray() && Array.getLength(obj) == 0) {
throw new IllegalArgumentException(message + " must be specified");
}
if (obj instanceof Collection && ((Collection) obj).isEmpty()) {
throw new IllegalArgumentException(message + " must be specified");
}
if (obj instanceof Map && ((Map) obj).isEmpty()) {
throw new IllegalArgumentException(message + " must be specified");
}
}
}
package cn.qg.qaplatform.mock.encrypt.paycenter;
public class ConfigureEncryptAndDecrypt {
public static final String CHAR_ENCODING = "UTF-8";
public static final String AES_ALGORITHM = "Aes/ECB/PKCS5Padding";
public static final String RSA_ALGORITHM = "Rsa/ECB/PKCS1Padding";
}
package cn.qg.qaplatform.mock.encrypt.paycenter;
import lombok.extern.slf4j.Slf4j;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
@Slf4j
public class Digest {
public static final String ENCODE = "UTF-8";
public static String signMD5(String aValue, String encoding) {
try {
byte[] input = aValue.getBytes(encoding);
MessageDigest md = MessageDigest.getInstance("MD5");
return AbstractConvertUtils.toHex(md.digest(input));
} catch (NoSuchAlgorithmException e) {
log.error("{}", e);
return null;
} catch (UnsupportedEncodingException e) {
log.error("{}", e);
return null;
}
}
public static String hmacSign(String aValue) {
try {
byte[] input = aValue.getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
return AbstractConvertUtils.toHex(md.digest(input));
} catch (NoSuchAlgorithmException e) {
log.error("{}", e);
return null;
}
}
public static String hmacSign(String aValue, String aKey) {
return hmacSign(aValue, aKey, ENCODE);
}
public static String hmacSign(String aValue, String aKey, String encoding) {
byte k_ipad[] = new byte[64];
byte k_opad[] = new byte[64];
byte keyb[];
byte value[];
try {
keyb = aKey.getBytes(encoding);
value = aValue.getBytes(encoding);
} catch (UnsupportedEncodingException e) {
keyb = aKey.getBytes();
value = aValue.getBytes();
}
Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);
Arrays.fill(k_opad, keyb.length, 64, (byte) 92);
for (int i = 0; i < keyb.length; i++) {
k_ipad[i] = (byte) (keyb[i] ^ 0x36);
k_opad[i] = (byte) (keyb[i] ^ 0x5c);
}
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
log.error("{}", e);
return null;
}
md.update(k_ipad);
md.update(value);
byte dg[] = md.digest();
md.reset();
md.update(k_opad);
md.update(dg, 0, 16);
dg = md.digest();
return AbstractConvertUtils.toHex(dg);
}
public static String hmacSHASign(String aValue, String aKey, String encoding) {
byte k_ipad[] = new byte[64];
byte k_opad[] = new byte[64];
byte keyb[];
byte value[];
try {
keyb = aKey.getBytes(encoding);
value = aValue.getBytes(encoding);
} catch (UnsupportedEncodingException e) {
keyb = aKey.getBytes();
value = aValue.getBytes();
}
Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);
Arrays.fill(k_opad, keyb.length, 64, (byte) 92);
for (int i = 0; i < keyb.length; i++) {
k_ipad[i] = (byte) (keyb[i] ^ 0x36);
k_opad[i] = (byte) (keyb[i] ^ 0x5c);
}
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException e) {
log.error("{}", e);
return null;
}
md.update(k_ipad);
md.update(value);
byte dg[] = md.digest();
md.reset();
md.update(k_opad);
md.update(dg, 0, 20);
dg = md.digest();
return AbstractConvertUtils.toHex(dg);
}
public static String digest(String aValue) {
return digest(aValue, ENCODE);
}
public static String digest(String aValue, String encoding) {
aValue = aValue.trim();
byte value[];
try {
value = aValue.getBytes(encoding);
} catch (UnsupportedEncodingException e) {
value = aValue.getBytes();
}
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException e) {
log.error("{}", e);
return null;
}
return AbstractConvertUtils.toHex(md.digest(value));
}
public static String digest(String aValue, String alg, String encoding) {
aValue = aValue.trim();
byte value[];
try {
value = aValue.getBytes(encoding);
} catch (UnsupportedEncodingException e) {
value = aValue.getBytes();
}
MessageDigest md = null;
try {
md = MessageDigest.getInstance(alg);
} catch (NoSuchAlgorithmException e) {
log.error("{}", e);
return null;
}
return AbstractConvertUtils.toHex(md.digest(value));
}
public static String udpSign(String aValue) {
try {
byte[] input = aValue.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("SHA1");
return new String(Base64.encode(md.digest(input)), ENCODE);
} catch (Exception e) {
return null;
}
}
}
package cn.qg.qaplatform.mock.encrypt.paycenter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.Map.Entry;
import java.util.TreeMap;
@Slf4j
public class EncryUtil {
/**
* 生成RSA签名
*/
public static String handleRSA(TreeMap<String, Object> map,
String privateKey) {
StringBuffer sbuffer = new StringBuffer();
for (Entry<String, Object> entry : map.entrySet()) {
sbuffer.append(entry.getValue());
}
String signTemp = sbuffer.toString();
String sign = "";
if (StringUtils.isNotEmpty(privateKey)) {
sign = Rsa.sign(signTemp, privateKey);
}
return sign;
}
/**
* 对易宝支付返回的结果进行验签
*
* @param data 易宝支付返回的业务数据密文
* @param encrypt_key 易宝支付返回的对ybAesKey加密后的密文
* @param yibaoPublickKey 易宝支付提供的公钥
* @param merchantPrivateKey 商户自己的私钥
* @return 验签是否通过
* @throws Exception
*/
public static boolean checkDecryptAndSign(String data, String encrypt_key,
String yibaoPublickKey, String merchantPrivateKey) {
/** 1.使用YBprivatekey解开aesEncrypt。 */
String AESKey;
try {
AESKey = Rsa.decrypt(encrypt_key, merchantPrivateKey);
} catch (Exception e) {
/** AES密钥解密失败 */
log.error("{}", e);
return false;
}
/** 2.用aeskey解开data。取得data明文 */
String realData = Aes.decryptFromBase64(data, AESKey);
TreeMap<String, String> map = JSON.parseObject(realData,
new TypeReference<TreeMap<String, String>>() {
});
/** 3.取得data明文sign。 */
String sign = StringUtils.trimToEmpty(map.get("sign"));
StringBuilder signData = new StringBuilder();
for (Entry<String, String> entry : map.entrySet()) {
if (StringUtils.equals(entry.getKey(), "sign")) {
continue;
}
signData.append(entry.getValue() == null ? "" : entry.getValue());
}
/** 5. result为true时表明验签通过 */
String str = signData.toString();
return Rsa.checkSign(str, sign,
yibaoPublickKey);
}
}
package cn.qg.qaplatform.mock.encrypt.paycenter;
import java.security.SecureRandom;
public class RandomUtil {
public static final SecureRandom random = new SecureRandom();
public static String getRandom(int length) {
StringBuilder ret = new StringBuilder();
for (int i = 0; i < length; i++) {
boolean isChar = (random.nextInt(2) % 2 == 0);// 输出字母还是数字
if (isChar) { // 字符串
int choice = random.nextInt(2) % 2 == 0 ? 65 : 97; // 取得大写字母还是小写字母
ret.append((char) (choice + random.nextInt(26)));
} else { // 数字
ret.append(Integer.toString(random.nextInt(10)));
}
}
return ret.toString();
}
}
package cn.qg.qaplatform.mock.encrypt.paycenter;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Rsa {
/**
* 指定key的大小
*/
private static int KEYSIZE = 1024;
/**
* 生成密钥对
*/
public static Map<String, String> generateKeyPair() throws Exception {
/** RSA算法要求有一个可信任的随机数源 */
SecureRandom sr = new SecureRandom();
/** 为RSA算法创建一个KeyPairGenerator对象 */
KeyPairGenerator kpg = KeyPairGenerator.getInstance("Rsa");
/** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
kpg.initialize(KEYSIZE, sr);
/** 生成密匙对 */
KeyPair kp = kpg.generateKeyPair();
/** 得到公钥 */
Key publicKey = kp.getPublic();
byte[] publicKeyBytes = publicKey.getEncoded();
String pub = new String(Base64.encodeBase64(publicKeyBytes),
ConfigureEncryptAndDecrypt.CHAR_ENCODING);
/** 得到私钥 */
Key privateKey = kp.getPrivate();
byte[] privateKeyBytes = privateKey.getEncoded();
String pri = new String(Base64.encodeBase64(privateKeyBytes),
ConfigureEncryptAndDecrypt.CHAR_ENCODING);
Map<String, String> map = new HashMap<String, String>();
map.put("publicKey", pub);
map.put("privateKey", pri);
RSAPublicKey rsp = (RSAPublicKey) kp.getPublic();
BigInteger bint = rsp.getModulus();
byte[] b = bint.toByteArray();
byte[] deBase64Value = Base64.encodeBase64(b);
String retValue = new String(deBase64Value);
map.put("modulus", retValue);
return map;
}
/**
* 加密方法 source: 源数据
*/
public static String encrypt(String source, String publicKey)
throws Exception {
Key key = getPublicKey(publicKey);
/** 得到Cipher对象来实现对源数据的RSA加密 */
Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] b = source.getBytes();
/** 执行加密操作 */
byte[] b1 = cipher.doFinal(b);
return new String(Base64.encodeBase64(b1),
ConfigureEncryptAndDecrypt.CHAR_ENCODING);
}
/**
* 解密算法 cryptograph:密文
*/
public static String decrypt(String cryptograph, String privateKey)
throws Exception {
Key key = getPrivateKey(privateKey);
/** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] b1 = Base64.decodeBase64(cryptograph.getBytes());
/** 执行解密操作 */
byte[] b = cipher.doFinal(b1);
return new String(b);
}
/**
* 得到公钥
*
* @param key 密钥字符串(经过base64编码)
* @throws Exception
*/
public static PublicKey getPublicKey(String key) throws Exception {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(
Base64.decodeBase64(key.getBytes()));
KeyFactory keyFactory = KeyFactory.getInstance("Rsa");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
/**
* 得到私钥
*
* @param key 密钥字符串(经过base64编码)
* @throws Exception
*/
public static PrivateKey getPrivateKey(String key) throws Exception {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(
Base64.decodeBase64(key.getBytes()));
KeyFactory keyFactory = KeyFactory.getInstance("Rsa");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
public static String sign(String content, String privateKey) {
String charset = ConfigureEncryptAndDecrypt.CHAR_ENCODING;
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
Base64.decodeBase64(privateKey.getBytes()));
KeyFactory keyf = KeyFactory.getInstance("Rsa");
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initSign(priKey);
signature.update(content.getBytes(charset));
byte[] signed = signature.sign();
return new String(Base64.encodeBase64(signed));
} catch (Exception e) {
}
return null;
}
public static boolean checkSign(String content, String sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("Rsa");
byte[] encodedKey = Base64.decode2(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
Signature signature = Signature
.getInstance("SHA1WithRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes("utf-8"));
boolean bverify = signature.verify(Base64.decode2(sign));
return bverify;
} catch (Exception e) {
log.error("{}", e);
}
return false;
}
}
package cn.qg.qaplatform.mock.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class Mock {
@TableId(type = IdType.AUTO)
private Integer id;
private String url;
private String description;
private String success;
private String fail;
/**
* 0-返回失败,1-返回成功
*/
private Integer flag;
/**
* 0-不加密,1-加密
*/
private Integer encrypt;
/**
* 1-json,2-字符串
*/
private Integer type;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
package cn.qg.qaplatform.mock.mapper;
import cn.qg.qaplatform.mock.entity.Mock;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface MockMapper extends BaseMapper<Mock> {
}
package cn.qg.qaplatform.mock.service;
import cn.qg.qaplatform.mock.entity.Mock;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
public interface MockService extends IService<Mock> {
}
package cn.qg.qaplatform.mock.service.impl;
import cn.qg.qaplatform.config.SwitchDataSource;
import cn.qg.qaplatform.mock.entity.Mock;
import cn.qg.qaplatform.mock.mapper.MockMapper;
import cn.qg.qaplatform.mock.service.MockService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MockServiceImpl extends ServiceImpl<MockMapper, Mock> implements MockService {
}
package cn.qg.qaplatform.mock.utils;
import cn.qg.qaplatform.utils.HttpClientUtils;
import com.alibaba.fastjson.JSONObject;
public class BankCardUtils {
public static String getCardCode(String cardNo) {
String url = "https://ccdcapi.alipay.com/validateAndCacheCardInfo.json?_input_charset=utf-8&cardNo=" + cardNo + "&cardBinCheck=true";
JSONObject resposne = HttpClientUtils.doGetReturnJson(url);
return resposne.get("bank").toString();
}
public static void main(String[] args) {
System.out.println(getBankName("CCB"));
}
public static String getBankName(String code){
int a = 0;
for (int i = 0; i < bankBin.length-165; i++) {
if(code.equals(bankBin[i+a])){
return bankBin[i+a+1];
}
a++;
}
return "";
}
private final static String[] bankBin = {
"SRCB", "深圳农村商业银行",
"BGB", "广西北部湾银行",
"SHRCB", "上海农村商业银行",
"BJBANK", "北京银行",
"WHCCB", "威海市商业银行",
"BOZK", "周口银行",
"KORLABANK", "库尔勒市商业银行",
"SPABANK", "平安银行",
"SDEB", "顺德农商银行",
"HURCB", "湖北省农村信用社",
"WRCB", "无锡农村商业银行",
"BOCY", "朝阳银行",
"CZBANK", "浙商银行",
"HDBANK", "邯郸银行",
"BOC", "中国银行",
"BOD", "东莞银行",
"CCB", "中国建设银行",
"ZYCBANK", "遵义市商业银行",
"SXCB", "绍兴银行",
"GZRCU", "贵州省农村信用社",
"ZJKCCB", "张家口市商业银行",
"BOJZ", "锦州银行",
"BOP", "平顶山银行",
"HKB", "汉口银行",
"SPDB", "上海浦东发展银行",
"NXRCU", "宁夏黄河农村商业银行",
"NYNB", "广东南粤银行",
"GRCB", "广州农商银行",
"BOSZ", "苏州银行",
"HZCB", "杭州银行",
"HSBK", "衡水银行",
"HBC", "湖北银行",
"JXBANK", "嘉兴银行",
"HRXJB", "华融湘江银行",
"BODD", "丹东银行",
"AYCB", "安阳银行",
"EGBANK", "恒丰银行",
"CDB", "国家开发银行",
"TCRCB", "江苏太仓农村商业银行",
"NJCB", "南京银行",
"ZZBANK", "郑州银行",
"DYCB", "德阳商业银行",
"YBCCB", "宜宾市商业银行",
"SCRCU", "四川省农村信用",
"KLB", "昆仑银行",
"LSBANK", "莱商银行",
"YDRCB", "尧都农商行",
"CCQTGB", "重庆三峡银行",
"FDB", "富滇银行",
"JSRCU", "江苏省农村信用联合社",
"JNBANK", "济宁银行",
"CMB", "招商银行",
"JINCHB", "晋城银行JCBANK",
"FXCB", "阜新银行",
"WHRCB", "武汉农村商业银行",
"HBYCBANK", "湖北银行宜昌分行",
"TZCB", "台州银行",
"TACCB", "泰安市商业银行",
"XCYH", "许昌银行",
"CEB", "中国光大银行",
"NXBANK", "宁夏银行",
"HSBANK", "徽商银行",
"JJBANK", "九江银行",
"NHQS", "农信银清算中心",
"MTBANK", "浙江民泰商业银行",
"LANGFB", "廊坊银行",
"ASCB", "鞍山银行",
"KSRB", "昆山农村商业银行",
"YXCCB", "玉溪市商业银行",
"DLB", "大连银行",
"DRCBCL", "东莞农村商业银行",
"GCB", "广州银行",
"NBBANK", "宁波银行",
"BOYK", "营口银行",
"SXRCCU", "陕西信合",
"GLBANK", "桂林银行",
"BOQH", "青海银行",
"CDRCB", "成都农商银行",
"QDCCB", "青岛银行",
"HKBEA", "东亚银行",
"HBHSBANK", "湖北银行黄石分行",
"WZCB", "温州银行",
"TRCB", "天津农商银行",
"QLBANK", "齐鲁银行",
"GDRCC", "广东省农村信用社联合社",
"ZJTLCB", "浙江泰隆商业银行",
"GZB", "赣州银行",
"GYCB", "贵阳市商业银行",
"CQBANK", "重庆银行",
"DAQINGB", "龙江银行",
"CGNB", "南充市商业银行",
"SCCB", "三门峡银行",
"CSRCB", "常熟农村商业银行",
"SHBANK", "上海银行",
"JLBANK", "吉林银行",
"CZRCB", "常州农村信用联社",
"BANKWF", "潍坊银行",
"ZRCBANK", "张家港农村商业银行",
"FJHXBC", "福建海峡银行",
"ZJNX", "浙江省农村信用社联合社",
"LZYH", "兰州银行",
"JSB", "晋商银行",
"BOHAIB", "渤海银行",
"CZCB", "浙江稠州商业银行",
"YQCCB", "阳泉银行",
"SJBANK", "盛京银行",
"XABANK", "西安银行",
"BSB", "包商银行",
"JSBANK", "江苏银行",
"FSCB", "抚顺银行",
"HNRCU", "河南省农村信用",
"COMM", "交通银行",
"XTB", "邢台银行",
"CITIC", "中信银行",
"HXBANK", "华夏银行",
"HNRCC", "湖南省农村信用社",
"DYCCB", "东营市商业银行",
"ORBANK", "鄂尔多斯银行",
"BJRCB", "北京农村商业银行",
"XYBANK", "信阳银行",
"ZGCCB", "自贡市商业银行",
"CDCB", "成都银行",
"HANABANK", "韩亚银行",
"CMBC", "中国民生银行",
"LYBANK", "洛阳银行",
"GDB", "广东发展银行",
"ZBCB", "齐商银行",
"CBKF", "开封市商业银行",
"H3CB", "内蒙古银行",
"CIB", "兴业银行",
"CRCBANK", "重庆农村商业银行",
"SZSBK", "石嘴山银行",
"DZBANK", "德州银行",
"SRBANK", "上饶银行",
"LSCCB", "乐山市商业银行",
"JXRCU", "江西省农村信用",
"ICBC", "中国工商银行",
"JZBANK", "晋中市商业银行",
"HZCCB", "湖州市商业银行",
"NHB", "南海农村信用联社",
"XXBANK", "新乡银行",
"JRCB", "江苏江阴农村商业银行",
"YNRCC", "云南省农村信用社",
"ABC", "中国农业银行",
"GXRCU", "广西省农村信用",
"PSBC", "中国邮政储蓄银行",
"BZMD", "驻马店银行",
"ARCU", "安徽省农村信用社",
"GSRCU", "甘肃省农村信用",
"LYCB", "辽阳市商业银行",
"JLRCU", "吉林农信",
"URMQCCB", "乌鲁木齐市商业银行",
"XLBANK", "中山小榄村镇银行",
"CSCB", "长沙银行",
"JHBANK", "金华银行",
"BHB", "河北银行",
"NBYZ", "鄞州银行",
"LSBC", "临商银行",
"BOCD", "承德银行",
"SDRCU", "山东农信",
"NCB", "南昌银行",
"TCCB", "天津银行",
"WJRCB", "吴江农商银行",
"CBBQS", "城市商业银行资金清算中心",
"HBRCU", "河北省农村信用社"
};
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment