params = [
120 | "amount" : '30.5',
121 | "currency" : 'UAH',
122 | "description": 'Balance replenishmenton on example.com',
123 | "order_id" : "1",
124 | 'result_url' : g.createLink(action: 'paymentResult', absolute: true).toString()]
125 | String button = liqpay.cnb_form(params);
126 | [button: button]
127 | }
128 | }
129 | ```
130 |
131 | And inside `grails-app/views/user/balanceReplenishment.gsp` you can output this button like this:
132 |
133 | ```gsp
134 |
135 | ${raw(button)}
136 |
137 | ```
138 |
139 |
140 | Changelog
141 | ---------
142 |
143 | [All releases](https://github.com/stokito/sdk-java/releases)
144 |
145 | ### v0.1 First Mavenized version.
146 |
147 | [Source](https://github.com/stokito/grails-cookie/releases/tag/v0.1)
148 |
149 | - Just reformatted code.
150 | - Created some basic tests.
151 | - API wasn't changed and this release can't broke compilation.
152 |
153 | ### v0.2 Improved tests
154 |
155 | [Source](https://github.com/stokito/grails-cookie/releases/tag/v0.2)
156 |
157 | - Refactoring
158 | - More tests coverage
159 | - Parameter `params` of methods `cnb_form()` and `api()` now can by any `Map`, not only `HashMap`.
160 | - API wasn't changed and this release can't broke compilation.
161 |
162 | ### v0.3 Some methods deprecated
163 |
164 | [Source](https://github.com/stokito/grails-cookie/releases/tag/v0.3)
165 |
166 | - Introduced API interface `LiqPayApi`
167 | - Deprecated fields that should be constant `host_checkout` and `liqpayApiUrl`. They was replaced with private constants.
168 | - Deprecated constructor `LiqPay(String publicKey, String privateKey, String liqpayApiUrl)` because `liqpayApiUrl` is constant and can't be rewritten.
169 | - Deprecated method `cnb_signature` because signature is already calculated inside `cnb_form(Map)`.
170 | - Deprecated shorthand method `setProxy(String host, Integer port)`, you should use full `setProxy(String host, Integer port, Proxy.Type)` instead. In next release v0.5 it will be deprecated too, and you should construct `Proxy` instance yourself.
171 | - API wasn't changed and this release can't broke compilation.
172 |
173 | ### v0.4 Last release that API compatible with old lib
174 |
175 | [Source](https://github.com/stokito/grails-cookie/releases/tag/v0.4)
176 |
177 | - This release is recommended if you used original old lib since it shouldn't break compilation.
178 | - Params `version` and `public_key` are always set inside `cnb_form()` and `api()` methods.
179 | - Old version of `cnb_form()` accepted `public_key` parameter that can be differ from `publicKey`initialized in constructor.
180 | - Methods `cnb_form()` and `api()` doesn't add `public_key` and `version` to instance of `params` method. I.e. now you can pass unmodifable map and reuse it without side effects.
181 | - API wasn't changed and this release can't broke compilation.
182 |
183 |
184 | ### v0.5 Removed deprecated methods
185 |
186 | [Source](https://github.com/stokito/grails-cookie/releases/tag/v0.5)
187 |
188 | - Removed deprecated method `cnb_signature` because signature is already calculated inside `cnb_form(Map)`.
189 | - Method `api()` now returns general `Map` instead of concrete `HashMap`.
190 | - Removed deprecated fields `liqpayApiUrl` and `host_checkout`. They replaced with constants `LiqPayApi.LIQPAY_API_URL` and `LiqPayApi.LIQPAY_API_CHECKOUT_URL`.
191 | - Introduced two new properties `proxyLogin` and `proxyPassword` that should be used instead of deprecated method `setProxyUser(login, password)`.
192 | - Introduced method `setProxy(Proxy)` that should be used instead of shorthand and deprecated `setProxy(host, port, Proxy.Type)`.
193 | - API **was changed** in this release and can broke compilation.
194 |
195 | ### v0.6 Enhanced usage
196 |
197 | [Source](https://github.com/stokito/grails-cookie/releases/tag/v0.6)
198 |
199 | - Created constructor `LiqPay(String publicKey, String privateKey, Proxy proxy, String proxyLogin, String proxyPassword)` that initialize API with proxy
200 | - Defined new property `isCnbSanbox()` that can globally set `sandbox` param in `cnb_form()` instead of specifying it always in `params`
201 |
202 |
203 | ### v0.7-SNAPSHOT
204 | - Changed url form liqpay.com to liqpay.ua
205 |
206 | ### v0.8-SNAPSHOT
207 | [Source]()
208 | - Changed cnb_form method. New form.
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 | com.liqpay
4 | liqpay-sdk
5 | jar
6 | LiqPay payments API
7 | 0.8-SNAPSHOT
8 | https://www.liqpay.ua/documentation/en
9 |
10 |
11 | The Apache Software License, Version 2.0
12 | http://www.apache.org/licenses/LICENSE-2.0.txt
13 |
14 |
15 |
16 | scm:git:https://github.com/stokito/sdk-java.git
17 | scm:git:git@github.com:stokito/sdk-java.git
18 | https://github.com/stokito/sdk-java
19 | HEAD
20 |
21 |
22 |
23 | bintray
24 | https://api.bintray.com/maven/stokito/maven/liqpay-sdk
25 |
26 |
27 |
28 |
29 | UTF-8
30 |
31 |
32 |
33 |
34 | com.googlecode.json-simple
35 | json-simple
36 | 1.1.1
37 |
38 |
39 | junit
40 | junit
41 | 4.13.1
42 | test
43 |
44 |
45 |
46 |
47 |
48 |
49 | org.apache.maven.plugins
50 | maven-compiler-plugin
51 | 3.2
52 |
53 | true
54 | 1.8
55 | 1.8
56 |
57 |
58 |
59 | maven-release-plugin
60 | 2.5.1
61 |
62 | false
63 | release
64 | true
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | release
73 |
74 |
75 |
76 | maven-source-plugin
77 | 2.4
78 |
79 |
80 | attach-sources
81 |
82 | jar
83 |
84 |
85 |
86 |
87 |
88 | maven-javadoc-plugin
89 | 2.10.1
90 |
91 |
92 | attach-javadocs
93 |
94 | jar
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/src/main/java/com/liqpay/LiqPay.java:
--------------------------------------------------------------------------------
1 | package com.liqpay;
2 |
3 | import org.json.simple.JSONObject;
4 | import org.json.simple.parser.JSONParser;
5 |
6 | import java.net.Proxy;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 | import java.util.TreeMap;
10 |
11 | import static com.liqpay.LiqPayUtil.base64_encode;
12 | import static com.liqpay.LiqPayUtil.sha1;
13 |
14 | public class LiqPay implements LiqPayApi {
15 | private final JSONParser parser = new JSONParser();
16 | private final String publicKey;
17 | private final String privateKey;
18 | private Proxy proxy;
19 | private String proxyLogin;
20 | private String proxyPassword;
21 | private boolean cnbSandbox;
22 | private boolean renderPayButton = true;
23 | // protected List supportedCurrencies = Arrays.asList("EUR", "UAH", "USD", "RUB", "GEL");
24 | // protected List supportedParams = Arrays.asList("public_key", "amount", "currency", "description", "order_id", "result_url", "server_url", "type", "signature", "language", "sandbox");
25 |
26 | public LiqPay(String publicKey, String privateKey) {
27 | this.publicKey = publicKey;
28 | this.privateKey = privateKey;
29 | checkRequired();
30 | }
31 |
32 | public LiqPay(String publicKey, String privateKey, Proxy proxy, String proxyLogin, String proxyPassword) {
33 | this.publicKey = publicKey;
34 | this.privateKey = privateKey;
35 | this.proxy = proxy;
36 | this.proxyLogin = proxyLogin;
37 | this.proxyPassword = proxyPassword;
38 | checkRequired();
39 | }
40 |
41 | private void checkRequired() {
42 | if (this.publicKey == null || this.publicKey.isEmpty()) {
43 | throw new IllegalArgumentException("publicKey is empty");
44 | }
45 | if (this.privateKey == null || this.privateKey.isEmpty()) {
46 | throw new IllegalArgumentException("privateKey is empty");
47 | }
48 | }
49 |
50 | public void setProxy(Proxy proxy) {
51 | this.proxy = proxy;
52 | }
53 |
54 | public Proxy getProxy() {
55 | return proxy;
56 | }
57 |
58 | public String getProxyLogin() {
59 | return proxyLogin;
60 | }
61 |
62 | public String getProxyPassword() {
63 | return proxyPassword;
64 | }
65 |
66 | public void setProxyLogin(String proxyLogin) {
67 | this.proxyLogin = proxyLogin;
68 | }
69 |
70 | public void setProxyPassword(String proxyPassword) {
71 | this.proxyPassword = proxyPassword;
72 | }
73 |
74 | public boolean isCnbSandbox() {
75 | return cnbSandbox;
76 | }
77 |
78 | public void setCnbSandbox(boolean cnbSandbox) {
79 | this.cnbSandbox = cnbSandbox;
80 | }
81 |
82 | public boolean isRenderPayButton() {
83 | return renderPayButton;
84 | }
85 |
86 | public void setRenderPayButton(boolean renderPayButton) {
87 | this.renderPayButton = renderPayButton;
88 | }
89 |
90 | @Override
91 | public Map api(String path, Map params) throws Exception {
92 | Map data = generateData(params);
93 | String resp = LiqPayRequest.post(LIQPAY_API_URL + path, data, this.getProxyLogin(), this.getProxyPassword(), this.getProxy());
94 | JSONObject jsonObj = (JSONObject) parser.parse(resp);
95 | return LiqPayUtil.parseJson(jsonObj);
96 | }
97 |
98 | protected Map generateData(Map params) {
99 | HashMap apiData = new HashMap<>();
100 | String data = base64_encode(JSONObject.toJSONString(withBasicApiParams(params)));
101 | apiData.put("data", data);
102 | apiData.put("signature", createSignature(data));
103 | return apiData;
104 | }
105 |
106 | protected TreeMap withBasicApiParams(Map params) {
107 | TreeMap tm = new TreeMap<>(params);
108 | tm.put("public_key", publicKey);
109 | tm.put("version", API_VERSION);
110 | return tm;
111 | }
112 |
113 | protected TreeMap withSandboxParam(TreeMap params) {
114 | if (params.get("sandbox") == null && isCnbSandbox()) {
115 | TreeMap tm = new TreeMap<>(params);
116 | tm.put("sandbox", "1");
117 | return tm;
118 | }
119 | return params;
120 | }
121 |
122 | protected String getBtnTxt(String lang) {
123 | switch (lang){
124 | case "ru":
125 | return "Оплатить";
126 | case "uk":
127 | return "Сплатити";
128 | case "en":
129 | return "Pay";
130 | default:
131 | return "Сплатити";
132 | }
133 | }
134 |
135 | @Override
136 | public String cnb_form(Map params) {
137 | checkCnbParams(params);
138 | String data = base64_encode(JSONObject.toJSONString(withSandboxParam(withBasicApiParams(params))));
139 | String signature = createSignature(data);
140 | String language = params.get("language") != null ? params.get("language") : DEFAULT_LANG;
141 | return renderHtmlForm(data, language, signature);
142 | }
143 |
144 | private String renderHtmlForm(String data, String language, String signature) {
145 | String form = "";
146 | form += "\n";
154 | return form;
155 | }
156 |
157 | protected void checkCnbParams(Map params) {
158 | if (params.get("amount") == null)
159 | throw new NullPointerException("amount can't be null");
160 | if (params.get("currency") == null)
161 | throw new NullPointerException("currency can't be null");
162 | if (params.get("description") == null)
163 | throw new NullPointerException("description can't be null");
164 | }
165 |
166 | protected String str_to_sign(String str) {
167 | return base64_encode(sha1(str));
168 | }
169 |
170 | protected String createSignature(String base64EncodedData) {
171 | return str_to_sign(privateKey + base64EncodedData + privateKey);
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/src/main/java/com/liqpay/LiqPayApi.java:
--------------------------------------------------------------------------------
1 | package com.liqpay;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | public interface LiqPayApi {
7 | String API_VERSION = "3";
8 | String LIQPAY_API_URL = "https://www.liqpay.ua/api/";
9 | String LIQPAY_API_CHECKOUT_URL = "https://www.liqpay.ua/api/3/checkout";
10 | String DEFAULT_LANG = "uk";
11 |
12 | Map api(String path, Map params) throws Exception;
13 |
14 | /**
15 | * Liq and Buy
16 | * Payment acceptance on the site client to server
17 | * To accept payments on your site you will need:
18 | * Register on www.liqpay.ua
19 | * Create a store in your account using install master
20 | * Get a ready HTML-button or create a simple HTML form
21 | * HTML form should be sent by POST to URL https://www.liqpay.ua/api/3/checkout Two parameters data and signature, where:
22 | * data - function result base64_encode( $json_string )
23 | * signature - function result base64_encode( sha1( $private_key . $data . $private_key ) )
24 | */
25 | String cnb_form(Map params);
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/liqpay/LiqPayRequest.java:
--------------------------------------------------------------------------------
1 | package com.liqpay;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.DataOutputStream;
5 | import java.io.InputStreamReader;
6 | import java.net.HttpURLConnection;
7 | import java.net.Proxy;
8 | import java.net.URL;
9 | import java.net.URLEncoder;
10 | import java.nio.charset.StandardCharsets;
11 | import java.util.Map;
12 |
13 | import static com.liqpay.LiqPayUtil.base64_encode;
14 |
15 | public class LiqPayRequest {
16 |
17 | public static String post(String url, Map list, String proxyLogin, String proxyPassword, Proxy proxy) throws Exception {
18 | String urlParameters = "";
19 |
20 | for (Map.Entry entry : list.entrySet())
21 | urlParameters += entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), "UTF-8") + "&";
22 |
23 | URL obj = new URL(url);
24 | DataOutputStream wr;
25 | BufferedReader in;
26 | HttpURLConnection con;
27 | if (proxy == null) {
28 | con = (HttpURLConnection) obj.openConnection();
29 | } else {
30 | con = (HttpURLConnection) obj.openConnection(proxy);
31 | if (proxyLogin != null)
32 | con.setRequestProperty("Proxy-Authorization", "Basic " + getProxyUser(proxyLogin, proxyPassword));
33 | }
34 | con.setRequestMethod("POST");
35 | con.setDoOutput(true);
36 | wr = new DataOutputStream(con.getOutputStream());
37 | // Send post request
38 | wr.writeBytes(urlParameters);
39 | wr.flush();
40 | wr.close();
41 | in = new BufferedReader(new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8));
42 |
43 | String inputLine;
44 | StringBuilder response = new StringBuilder();
45 |
46 | while ((inputLine = in.readLine()) != null) {
47 | response.append(inputLine);
48 | }
49 | in.close();
50 | return response.toString();
51 | }
52 |
53 | public static String getProxyUser(String proxyLogin, String proxyPassword) {
54 | return base64_encode(proxyLogin + ":" + proxyPassword);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/liqpay/LiqPayUtil.java:
--------------------------------------------------------------------------------
1 | package com.liqpay;
2 |
3 | import java.security.MessageDigest;
4 | import java.text.ParseException;
5 | import java.util.ArrayList;
6 | import java.util.HashMap;
7 | import java.util.Set;
8 |
9 | import javax.xml.bind.DatatypeConverter;
10 |
11 | import org.json.simple.JSONArray;
12 | import org.json.simple.JSONObject;
13 |
14 | public class LiqPayUtil {
15 | public static byte[] sha1(String param) {
16 | try {
17 | MessageDigest SHA = MessageDigest.getInstance("SHA-1");
18 | SHA.reset();
19 | SHA.update(param.getBytes("UTF-8"));
20 | return SHA.digest();
21 | } catch (Exception e) {
22 | throw new RuntimeException("Can't calc SHA-1 hash", e);
23 | }
24 | }
25 |
26 | public static String base64_encode(byte[] bytes) {
27 | return DatatypeConverter.printBase64Binary(bytes);
28 | }
29 |
30 | public static String base64_encode(String data) {
31 | return base64_encode(data.getBytes());
32 | }
33 |
34 | public static ArrayList