Advertisement
Guest User

Untitled

a guest
Apr 4th, 2018
324
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.05 KB | None | 0 0
  1. package server;
  2.  
  3. import java.io.BufferedOutputStream;
  4. import java.io.ByteArrayOutputStream;
  5. import java.io.File;
  6. import java.io.*;
  7. import java.io.FileInputStream;
  8. import java.io.FileNotFoundException;
  9. import java.io.FileOutputStream;
  10. import java.io.IOException;
  11. import java.io.InputStream;
  12. import java.io.ObjectOutputStream;
  13. import java.io.OutputStream;
  14. import java.io.PrintStream;
  15. import java.rmi.*;
  16. import java.rmi.server.*;
  17. import java.security.Certificate;
  18. import java.security.GeneralSecurityException;
  19. import java.security.InvalidKeyException;
  20. import java.security.Key;
  21. import java.security.KeyFactory;
  22. import java.security.KeyPair;
  23. import java.security.KeyPairGenerator;
  24. import java.security.KeyStore;
  25. import java.security.KeyStore.PrivateKeyEntry;
  26. import java.security.KeyStore.ProtectionParameter;
  27. import java.security.KeyStoreException;
  28. import java.security.NoSuchAlgorithmException;
  29. import java.security.NoSuchProviderException;
  30. import java.security.PrivateKey;
  31. import java.security.PublicKey;
  32. import java.security.spec.*;
  33. import java.security.*;
  34. import java.security.SignatureException;
  35. import java.security.UnrecoverableKeyException;
  36. import java.security.cert.CertificateException;
  37. import java.security.cert.X509Certificate;
  38. import java.security.spec.InvalidKeySpecException;
  39. import java.security.spec.PKCS8EncodedKeySpec;
  40. import java.security.spec.X509EncodedKeySpec;
  41. import java.sql.*;
  42. import java.util.*;
  43. import java.util.Date;
  44. import sun.security.tools.keytool.CertAndKeyGen;
  45. import sun.security.x509.*;
  46.  
  47.  
  48. public class HDSBank extends UnicastRemoteObject implements HDSBankInterface {
  49.  
  50. private int count;
  51. private PublicKey pubkey;
  52. private PrivateKey privkey;
  53. private Transaction transaction;
  54. private String username;
  55. ArrayList<Account> accounts;
  56.  
  57. private String keyStorePw;
  58.  
  59. // JDBC driver name and database URL
  60. String JDBC_DRIVER = "com.mysql.jdbc.Driver";
  61. String DB_URL = "jdbc:mysql://localhost:3306/bankDB?verifyServerCertificate=false&useSSL=true";
  62.  
  63. // Database credentials
  64. String USER = "root";
  65. String PASS = "root"; // TODO this shouldn't be here
  66.  
  67. Connection conn = null;
  68. // Statement stmt = null; // this isn't used!!
  69.  
  70. public HDSBank(String pw) throws IOException, GeneralSecurityException {
  71. this.keyStorePw = pw;
  72. try {
  73. Class.forName(JDBC_DRIVER); // Load jdbc driver
  74. System.out.println("Driver Loaded");
  75.  
  76. // Open Connection
  77. System.out.println("Connecting to a selected database...");
  78. conn = DriverManager.getConnection(DB_URL, USER, PASS);
  79. System.out.println("====Connected database successfully===");
  80. } catch (Exception e) {
  81. System.out.println(e);
  82. // error handling code
  83. }
  84. File f = new File("keystores/server/serverKeyStore");
  85. if(f.exists() && !f.isDirectory()) {
  86. loadKeystore();
  87. }
  88. else {
  89. createKeystore();
  90. generateAndSave();
  91. }
  92.  
  93. transaction = new Transaction();
  94. transaction.setDBConnection(conn);
  95. }
  96.  
  97.  
  98.  
  99. public boolean login(String username, String password) throws RemoteException, SQLException, NoSuchAlgorithmException, InvalidKeySpecException{
  100. // TODO see if client exists already or not, create a function
  101.  
  102. String queryUsername = "SELECT username, publicKey FROM User WHERE username = ? AND pw = ?";
  103. PreparedStatement stmt = (PreparedStatement) conn.prepareStatement(queryUsername);
  104. stmt.setString(1, username);
  105. stmt.setString(2, password);
  106. // stmt.setString(2, password);
  107. ResultSet rs = stmt.executeQuery();
  108.  
  109. if (rs.next()) {
  110. // user logado
  111. this.username = rs.getString("username");
  112. System.out.println("New Client logged in: "+this.username);
  113. /*
  114. TODO isto da erro se nao receber uma PUBKEY, ta a receber int pq tamos a testar e da erro, depois e descomentar
  115. try {
  116. // PublicKey pubk = convertStringToPubKey(pubString);
  117. System.out.println(pubk);
  118. } catch (Exception e) {
  119. System.out.println(e);
  120. // error handling code
  121. }
  122. System.exit(0);
  123. <<<<<<< HEAD
  124. */
  125. //this.userLoggedIn = new Account(username, password, pubk); quando usarmos as pubkeys e so descomentar
  126. return true;
  127. } else {
  128. // username ou pass errados
  129. System.out.println("Username no bueno");
  130. return false;
  131. }
  132.  
  133. } // end of login function
  134.  
  135. protected Connection getDBConnection() {
  136. return this.conn;
  137. }
  138.  
  139. public String say(String m) throws RemoteException {
  140. count++;
  141. System.out.println("Received msg: " + m);
  142. return m + count;
  143. }
  144.  
  145. public String send_amount(String senderUsername, String receiverUsername, double amount, String nonce, String sendSignature) throws RemoteException, SignatureException, InvalidKeyException, NoSuchAlgorithmException, SQLException, UnsupportedEncodingException {
  146. // IMPLEMENT VERIFY THE SIGNATURE IS LEGIT OR NOT
  147. System.out.println("11111111");
  148. String senderpubkey = getPubKeyStrByUsername(senderUsername);
  149. System.out.println("222222222");
  150. String receiverpubkey = getPubKeyStrByUsername(receiverUsername);
  151. System.out.println("fodasseeeeeeeeeeeeeeeee");
  152. if(checkUserExists(receiverUsername)) {
  153. /*if(verifySignature(senderUsername, receiverUsername, amount, nonce, sendSignature)){
  154. System.out.println(nonce);
  155. System.out.println(senderUsername);
  156. System.out.println(receiverUsername);
  157. System.out.println(amount);
  158. System.out.println(sendSignature);
  159. String rs = "";
  160. try {
  161. System.out.println("ola");
  162. rs = transaction.sendDBTransaction(senderpubkey, receiverpubkey, convertPubKeyToString(this.pubkey), amount, "s", nonce, sendSignature, "send");
  163. if(rs.equals("You dont have enough money")) {
  164. return "NoMoney";
  165. }
  166. else if(rs.equals("Sent")) {
  167. return "Sent";
  168. }
  169. } catch (Exception e) {
  170. e.printStackTrace();
  171. }
  172.  
  173. }else{
  174. return "Error";
  175. }*/
  176. String rs = "";
  177. System.out.println("***********************");
  178. System.out.println("USER EXISTS");
  179. try {
  180. System.out.println("ola");
  181. rs = transaction.sendDBTransaction(senderpubkey, receiverpubkey, convertPubKeyToString(this.pubkey), amount, "s", nonce, sendSignature, "send");
  182. System.out.println("hmm");
  183. if(rs.equals("You dont have enough money")) {
  184. return "NoMoney";
  185. }
  186. else if(rs.equals("Sent")) {
  187. return "Sent";
  188. }
  189. } catch (Exception e) {
  190. e.printStackTrace();
  191. }
  192. }
  193. else {
  194. return "NoUser";
  195. }
  196. return "Error";
  197. }
  198.  
  199. public boolean receive_amount(String senderstrpubkey, String receiverstrpubkey, double amount) throws RemoteException {
  200. =======
  201. */
  202. //this.userLoggedIn = new Account(username, password, pubk); quando usarmos as pubkeys e so descomentar
  203. return true;
  204. } else {
  205. // username ou pass errados
  206. System.out.println("Username no bueno");
  207. return false;
  208. }
  209.  
  210. } // end of login function
  211.  
  212. protected Connection getDBConnection() {
  213. return this.conn;
  214. }
  215.  
  216. public String say(String m) throws RemoteException {
  217. count++;
  218. System.out.println("Received msg: " + m);
  219. return m + count;
  220. }
  221.  
  222.  
  223.  
  224. public boolean receive_amount(String senderstrpubkey, String receiverstrpubkey, double amount) throws RemoteException {
  225. boolean success = false;
  226. try {
  227. success = transaction.receiveDBTransaction(senderstrpubkey, receiverstrpubkey, "keydosv", amount, "r", "nonce", "mac", "send");
  228. } catch (NoSuchAlgorithmException e) {
  229. e.printStackTrace();
  230. }
  231. <<<<<<< HEAD
  232.  
  233. public String register(PublicKey clientPubKey, String username, String passhash, String name)
  234. throws RemoteException, SQLException {
  235. // returns pubkey of server? doesn't client already know? what else?
  236.  
  237. System.out.println("=== Register Request Received ===");
  238. System.out.println("Username: " + username);
  239. System.out.println("Name: " + name);
  240. System.out.println("Passhash: " + passhash);
  241.  
  242. int exists = checkUserExists(username, clientPubKey);
  243.  
  244. if (exists == 0) {
  245. Account acc = new Account(username, passhash, clientPubKey);
  246. if (createAccount(clientPubKey, username, passhash, name)) {
  247. System.out.println("User created Successfully!");
  248. this.username = username;
  249. return "User created Successfully!";
  250. }
  251. // accounts.add(acc); TODO register Joao!!!!
  252. } else if (exists == 1) {
  253. return "Username is unavailable";
  254. } else if (exists == 2) {
  255. return "Public Key is unavailable";
  256. =======
  257. return success;
  258. }
  259.  
  260.  
  261. public ArrayList<String> check_account() throws RemoteException, SQLException {
  262. System.out.println("=== Check Account Request Received ===");
  263.  
  264. String query = "SELECT Amount FROM User WHERE username = ?";
  265. PreparedStatement stmt = (PreparedStatement) conn.prepareStatement(query);
  266. stmt.setString(1, this.username);
  267. System.out.println("Ola");
  268. //System.out.println(this.userLoggedIn.getUsername());
  269. ResultSet rs = stmt.executeQuery();
  270.  
  271. if (rs.next()) {
  272. String rsamount = rs.getString("Amount");
  273. ArrayList<String> trans = getPendingTransactions();
  274. String bal = "Your Balance: " + rsamount + " euros";
  275. System.out.println(rsamount);
  276. trans.add(0, bal);
  277. return trans;
  278. }
  279. return null;
  280. }
  281.  
  282. public Object[] audit(PublicKey accountPubKey) throws RemoteException {
  283. return null;
  284. }
  285.  
  286. //////////////////////////////////////////////// AUX FUNCTIONS ///////////////////////////////////////////////////////////////////////
  287.  
  288.  
  289. private boolean createAccount(PublicKey pubkey, String username, String passhash, String name) throws SQLException {
  290.  
  291. String query = "INSERT INTO User(publicKey, username, pw, Name, Amount) VALUES (?, ?, ?, ?, ?)";
  292. PreparedStatement stmt = (PreparedStatement) conn.prepareStatement(query);
  293.  
  294. stmt.setString(1, convertPubKeyToString(pubkey));
  295. stmt.setString(2, username);
  296. stmt.setString(3, passhash);
  297. stmt.setString(4, name);
  298. stmt.setInt(5, 5);
  299.  
  300. stmt.executeUpdate();
  301.  
  302. return true;
  303. }
  304.  
  305. private int checkUserExists(String username, PublicKey pub) throws SQLException {
  306. String query = "SELECT * FROM User WHERE username = ?";
  307. PreparedStatement stmt = (PreparedStatement) conn.prepareStatement(query);
  308. stmt.setString(1, username);
  309. ResultSet rs = stmt.executeQuery();
  310.  
  311. if (rs.next()) {
  312. String rsuser = rs.getString("username");
  313. System.out.println("Username " + rsuser + " is unavailable");
  314. return 1;
  315. }
  316.  
  317. <<<<<<< HEAD
  318. private boolean checkUserExists(String username) throws SQLException {
  319. String query = "SELECT * FROM User WHERE username = ?";
  320. PreparedStatement stmt = (PreparedStatement) conn.prepareStatement(query);
  321. stmt.setString(1, username);
  322. ResultSet rs = stmt.executeQuery();
  323.  
  324. if (rs.next()) {
  325. String rsuser = rs.getString("username");
  326. System.out.println("Username " + rsuser + " exists");
  327. return true;
  328. }
  329. return false;
  330. }
  331.  
  332.  
  333.  
  334. private String convertPubKeyToString(PublicKey pub) {
  335. byte[] publicKeyBytes = pub.getEncoded();
  336. String pubkeyStr = Base64.getEncoder().encodeToString(publicKeyBytes);
  337. return pubkeyStr;
  338. }
  339. =======
  340. query = "SELECT * FROM User WHERE publicKey = ?";
  341. stmt = (PreparedStatement) conn.prepareStatement(query);
  342. stmt.setString(1, convertPubKeyToString(pub));
  343. rs = stmt.executeQuery();
  344. >>>>>>> 564c3f6e44429e773a161ed8cb6fe2c038a7394b
  345.  
  346. if (rs.next()) {
  347. System.out.println("PublicKey is unavailable");
  348. return 2;
  349. }
  350. return 0;
  351. }
  352.  
  353. private String convertPubKeyToString(PublicKey pub) {
  354. byte[] publicKeyBytes = pub.getEncoded();
  355. String pubkeyStr = Base64.getEncoder().encodeToString(publicKeyBytes);
  356. return pubkeyStr;
  357. }
  358.  
  359. private PublicKey convertStringToPubKey(String pubString) throws NoSuchAlgorithmException, InvalidKeySpecException {
  360. byte[] publicBytes = Base64.getDecoder().decode(pubString);
  361. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
  362. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  363. PublicKey pubKey = keyFactory.generatePublic(keySpec);
  364. return pubKey;
  365. }
  366.  
  367. private ArrayList<String> getPendingTransactions() throws SQLException {
  368. ArrayList<String> result = new ArrayList<String>();
  369.  
  370.  
  371. String query = "SELECT *"
  372. + " FROM Transaction "
  373. + "WHERE publicKeyDestiny = ?";
  374. PreparedStatement stmt = (PreparedStatement) conn.prepareStatement(query);
  375. //String sourcePub = getPubKeyStrByUsername(this.userLoggedIn.getUsername()); USE MEEEEEE
  376. String sourcePub = "1"; // DELETE MEEEEEE
  377. stmt.setString(1, sourcePub);
  378. ResultSet rs = stmt.executeQuery();
  379.  
  380. if(rs.next()) {
  381. result.add("Pending Transactions:");
  382. result.add("| Transaction ID | User | Type |"
  383. + " Source Public Key | Amount |");
  384. String id = rs.getString("idTransaction");
  385. String fkUser = rs.getString("fkUser");
  386. String type = rs.getString("type");
  387. String publicKeySource = rs.getString("publicKeySource");
  388. String amount = rs.getString("amount");
  389.  
  390. result.add(id);
  391. result.add(fkUser);
  392. result.add(type);
  393. result.add(publicKeySource);
  394. result.add(amount);
  395. result.add("=");
  396.  
  397. while(rs.next()) {
  398. id = rs.getString("idTransaction");
  399. fkUser = rs.getString("fkUser");
  400. type = rs.getString("type");
  401. publicKeySource = rs.getString("publicKeySource");
  402. amount = rs.getString("amount");
  403.  
  404. result.add(id);
  405. result.add(fkUser);
  406. result.add(type);
  407. result.add(publicKeySource);
  408. result.add(amount);
  409. result.add("=");
  410. }
  411. }
  412. else {
  413. result.add("No Pending Transactions");
  414. }
  415. return result;
  416.  
  417. }
  418.  
  419.  
  420. private String getPubKeyStrByUsername(String username) throws SQLException {
  421. String query = "SELECT publicKey FROM User WHERE username = ?";
  422. PreparedStatement stmt = (PreparedStatement) conn.prepareStatement(query);
  423. stmt.setString(1, username);
  424. ResultSet rs = stmt.executeQuery();
  425.  
  426. if(rs.next()) {
  427. String rsPub = rs.getString("publicKey");
  428. return rsPub;
  429. }
  430. return null;
  431. }
  432. ////////////////////////////////////////////////////////// SECURITY FUNCTIONS ////////////////////////////////////////////////////////
  433. boolean verifySignature(String senderstrpubkey, String receiverstrpubkey, double amount, String nonce, String sentSignature) throws SQLException, NoSuchAlgorithmException, InvalidKeySpecException, SignatureException, InvalidKeyException, UnsupportedEncodingException {
  434.  
  435. // first we need to get the public key of the user logged in
  436. String senderpubkeystrfromsv = getPubKeyStrByUsername(this.username);
  437.  
  438. PublicKey senderpubkey = convertStringToPubKey(senderpubkeystrfromsv);
  439.  
  440. System.out.println("ASSINATURA\n\n" + sentSignature);
  441. System.out.println("\n\n");
  442. System.out.println("1\n\n" + senderpubkeystrfromsv);
  443.  
  444. Signature signature = Signature.getInstance("SHA1WithRSA");
  445.  
  446. try{
  447. System.out.println("ola");
  448. } catch (Exception e){
  449. System.out.println(e);
  450. }
  451.  
  452.  
  453. //signature.initVerify();
  454.  
  455. byte[] signatureBytes = Base64.getDecoder().decode(sentSignature);
  456.  
  457.  
  458.  
  459. // the fields sent FROM THE CLIENT
  460. byte[] data0 = senderstrpubkey.getBytes("UTF8");
  461. byte[] data1 = receiverstrpubkey.getBytes("UTF8");
  462. byte[] data2 = String.valueOf(amount).getBytes("UTF8");
  463. byte[] data3 = nonce.getBytes("UTF8");
  464.  
  465. System.out.println("VERYFYING\n" + signatureBytes);
  466.  
  467. try{
  468. signature.initVerify(senderpubkey);
  469. } catch ( Exception e){
  470. System.out.println(e);
  471. }
  472. System.out.println("1");
  473. signature.update(data0);
  474. signature.update(data1);
  475. signature.update(data2);
  476. signature.update(data3);
  477. System.out.println("2");
  478.  
  479. try{
  480. boolean verified = signature.verify(signatureBytes);
  481. if (verified) {
  482. System.out.println("Data verified.");
  483. } else {
  484. System.out.println("Cannot verify data.");
  485. }
  486. } catch ( Exception e){
  487. System.out.println(e);
  488. }
  489.  
  490.  
  491.  
  492. <<<<<<< HEAD
  493. private void createKeystore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
  494. char[] password = this.keyStorePw.toCharArray();
  495. KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
  496. ks.load(null, password);
  497. FileOutputStream fos = new FileOutputStream("keystores/server/serverKeyStore");
  498. ks.store(fos, password);
  499. fos.close();
  500. }
  501.  
  502. private void loadKeystore() throws IOException, UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, CertificateException {
  503. char[] password = this.keyStorePw.toCharArray();
  504. =======
  505. System.exit(0);
  506. return true;
  507.  
  508. }
  509.  
  510. >>>>>>> 564c3f6e44429e773a161ed8cb6fe2c038a7394b
  511.  
  512.  
  513. <<<<<<< HEAD
  514. Key priv = keystore.getKey("HDSBank", password);
  515. this.privkey = (PrivateKey) priv;
  516. if (this.privkey instanceof PrivateKey) {
  517. X509Certificate cert = (X509Certificate) keystore.getCertificate("HDSBank");
  518. this.pubkey = cert.getPublicKey();
  519. }
  520. }
  521.  
  522. private void generateAndSave() throws GeneralSecurityException, IOException {
  523. char[] password = this.keyStorePw.toCharArray();
  524.  
  525. KeyStore ks = KeyStore.getInstance("JKS");
  526. InputStream readStream = new FileInputStream("keystores/server/serverKeyStore");
  527. ks.load(readStream, password);
  528.  
  529. X509Certificate[] certChain = generateCertificate();
  530. ks.setKeyEntry("HDSBank", this.privkey, password, certChain);
  531. OutputStream writeStream = new FileOutputStream("keystores/server/serverKeyStore");
  532. ks.store(writeStream, password);
  533. this.privkey = (PrivateKey) ks.getKey("HDSBank", password);
  534. this.pubkey = certChain[0].getPublicKey();
  535. =======
  536.  
  537. ////////////////////////////////////////////////////////// KEY FUNCTIONS ////////////////////////////////////////////////////////////
  538.  
  539. private void createKeystore(String pw) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
  540.  
  541. char[] password = this.keyStorePw.toCharArray();
  542. KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
  543. ks.load(null, password);
  544. FileOutputStream fos = new FileOutputStream("keystores/server/serverKeyStore");
  545. ks.store(fos, password);
  546. fos.close();
  547. }
  548.  
  549. private void loadKeystore(String pw) throws IOException, UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, CertificateException {
  550. char[] password = this.keyStorePw.toCharArray();
  551.  
  552. FileInputStream is = new FileInputStream("keystores/server/serverKeyStore");
  553. KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
  554. keystore.load(is, password);
  555.  
  556. Key priv = keystore.getKey("HDSBank", password);
  557. this.privkey = (PrivateKey) priv;
  558. >>>>>>> 564c3f6e44429e773a161ed8cb6fe2c038a7394b
  559.  
  560. if (this.privkey instanceof PrivateKey) {
  561. X509Certificate cert = (X509Certificate) keystore.getCertificate("HDSBank");
  562. this.pubkey = cert.getPublicKey();
  563. }
  564. }
  565.  
  566. <<<<<<< HEAD
  567. private X509Certificate[] generateCertificate() throws GeneralSecurityException, IOException {
  568. try{
  569. CertAndKeyGen keyGen = new CertAndKeyGen("RSA","SHA1WithRSA",null);
  570. keyGen.generate(1024);
  571. this.pubkey = keyGen.getPublicKey();
  572. this.privkey = keyGen.getPrivateKey();
  573. //Generate self signed certificate
  574. X509Certificate[] chain=new X509Certificate[1];
  575. chain[0]=keyGen.getSelfCertificate(new X500Name("CN=HDSBank"), (long)365*24*3600);
  576. =======
  577. private void generateAndSave(String pw) throws GeneralSecurityException, IOException {
  578. char[] password = this.keyStorePw.toCharArray();
  579.  
  580. KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
  581. kpg.initialize(1024);
  582. KeyPair kp = kpg.generateKeyPair();
  583. >>>>>>> 564c3f6e44429e773a161ed8cb6fe2c038a7394b
  584.  
  585. KeyStore ks = KeyStore.getInstance("JKS");
  586. InputStream readStream = new FileInputStream("keystores/server/serverKeyStore");
  587. ks.load(readStream, password);
  588.  
  589. X509Certificate[] certChain = generateCertificate("HDSBank", kp, 360, "RSA");
  590. ks.setKeyEntry("HDSBank", kp.getPrivate(), password, certChain);
  591. OutputStream writeStream = new FileOutputStream("keystores/server/serverKeyStore");
  592. ks.store(writeStream, password);
  593.  
  594. this.privkey = (PrivateKey) ks.getKey("HDSBank", password);
  595. this.pubkey = certChain[0].getPublicKey();
  596.  
  597. writeStream.close();
  598. }
  599.  
  600. private X509Certificate[] generateCertificate(String dn, KeyPair pair, int days, String algorithm) throws GeneralSecurityException, IOException {
  601. try{
  602. CertAndKeyGen keyGen=new CertAndKeyGen("RSA","SHA1WithRSA",null);
  603. keyGen.generate(1024);
  604.  
  605. //Generate self signed certificate
  606. X509Certificate[] chain=new X509Certificate[1];
  607. chain[0]=keyGen.getSelfCertificate(new X500Name("CN=HDSBank"), (long)365*24*3600);
  608.  
  609. return chain;
  610. }catch(Exception ex){
  611. ex.printStackTrace();
  612. }
  613. return null;
  614.  
  615. }
  616. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement