diff --git a/.gitignore b/.gitignore index 79301d6..57819f7 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ go.work.sum # env file .env wallet.db +uploads/ \ No newline at end of file diff --git a/README.md b/README.md index ae0f052..69b1195 100644 --- a/README.md +++ b/README.md @@ -10,19 +10,21 @@ go run wallet.go ### Curl request to create a new user ``` -curl -X POST http://localhost:8080/create -d '{"email":"","password":"","name":""}' +curl -X POST http://localhost:8080/create -d '{"email":"","password":"","name":"","secret_key":""}' ``` +_**Note** : If `secret_key` is not provided explicitly, password will be used as `secret_key`_ + #### sample with valid request ``` -curl -X POST http://localhost:8080/create -d '{"email":"jiya@p.com","password":"123","name":"jiya"}' +curl -X POST http://localhost:8080/create -d '{"email":"mani@p.com","password":"123","name":"mani","secret_key":"abc123"}' ``` **Response:** ``` -{"did":"bafybmie5l4jpfxmnnqi3sk4vnt6fx3sbuzf632ubeflc7let6rljzq4usi"} +{"did":"bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvaina","email":"mani@p.com","name":"mani"} ``` #### sample with invalid request (invalid input format to name) ``` -curl -X POST http://localhost:8080/create -d '{"email":"jiya@p.com","password":"123","name":jiya}' +curl -X POST http://localhost:8080/create -d '{"email":"jiya@p.com","password":"123","name":jiya,"secret_key":"abc123"}' ``` **Response:** ``` @@ -68,19 +70,19 @@ curl -L -X POST http://localhost:8080/register_did -H 'Authorization: Bearer " -H 'Author ``` #### sample with valid request ``` -curl -L -X GET "http://localhost:8080/request_balance?did=bafybmigfq7dnhqdpghluqfirvn5yz76vpvrkutofswih7sidmqmssohvbq" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzU4MTY2NTAsInN1YiI6ImJhZnlibWlnZnE3ZG5ocWRwZ2hsdXFmaXJ2bjV5ejc2dnB2cmt1dG9mc3dpaDdzaWRtcW1zc29odmJxIn0.c3CFWttRFrm3KKlCi8uazISOekI_T1PvV9jLsObREqE' +curl -L -X GET "http://localhost:8080/request_balance?did=bafybmihsnmqer6f6rifz5mg5elf7uwt3en6t35vics7y5y7pn4anyt4wb4" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3MjE4MTQsInN1YiI6ImJhZnlibWloc25tcWVyNmY2cmlmejVtZzVlbGY3dXd0M2VuNnQzNXZpY3M3eTV5N3BuNGFueXQ0d2I0In0.LiYfB_qFd13TpsxeGgoi3f2pDsZ7RDAeqzG1vtNTbu0' ``` **Response:** ``` -{"account_info":[{"did":"bafybmigfq7dnhqdpghluqfirvn5yz76vpvrkutofswih7sidmqmssohvbq","did_type":0,"locked_rbt":0,"pinned_rbt":0,"pledged_rbt":14.824,"rbt_amount":5.176}],"message":"Got account info successfully","result":null,"status":true} +{"status":true,"message":"Got account info successfully","result":[{"did":"bafybmihsnmqer6f6rifz5mg5elf7uwt3en6t35vics7y5y7pn4anyt4wb4","did_type":0,"locked_rbt":0,"pinned_rbt":0,"pledged_rbt":0,"rbt_amount":1}]} ``` #### sample with invalid request (empty input to did) ``` -curl -L -X GET "http://localhost:8080/request_balance?did=" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzU0NjY4MjIsInN1YiI6ImJhZnlibWlmZWJxbHZxMnVldHhvM21ncnd1Z2YzazRyZGp1cG82aDZma243bXpyYjVla2h4dHRhbW5xIn0.NeIFZ0BitoO5hEaMF_fZbyyCGD2b4jh9FVM4536VMFI' +curl -L -X GET "http://localhost:8080/request_balance?did=" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3MjE4MTQsInN1YiI6ImJhZnlibWloc25tcWVyNmY2cmlmejVtZzVlbGY3dXd0M2VuNnQzNXZpY3M3eTV5N3BuNGFueXQ0d2I0In0.LiYfB_qFd13TpsxeGgoi3f2pDsZ7RDAeqzG1vtNTbu0' ``` **Response:** ``` -{"error":"Missing required parameter: did"} +{"status":false,"message":"Missing required parameter: did","result":null} ``` @@ -180,19 +182,19 @@ curl -L -X POST http://localhost:8080/rbt/unpledge -H 'Authorization: Bearer ","sign_data ``` #### sample with valid request ``` -curl -X POST http://localhost:8080/sign -d '{"did":"bafybmifqpi36mvzocqqpsh3rtjrjy5434wlqv4nz7zr4ejqx3qul5gl36q","sign_data":{"hash":"YmY0ZGI0NDEzNWZkYTg2Nzc1YTg1ZWQzMTRjZmIyZTI0MmVmZjBjYzdmOTI3OWNiYzVkZmQ5NjAxMTNkNDlhYQ==","id":"0319B7FA-F9CF-4019-97AB-FA5D69608735","mode":4}}' +curl -X POST http://localhost:8080/sign -d '{"did":"bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvaina","sign_data":{"hash":"NDkzYTkyN2NjYTA1YTgzZDA1ZWVjZjcwMzgxYjQ5ZGY1YTFlOTNiODM0OTE5OWJiYWY4NGVmNjBkNDdkMTEzNA==","id":"4CC6CE58-3C12-4CCB-B0D3-05395D4E3650","mode":4, "only_priv_key":true}}' ``` **Response:** -while transacting RBTs +(While registering DID) ``` -"\"Transfer finished successfully in 6.679579318s with trnxid 7c57df13b39e7eed7c5980eb4e4b78f0eadee662cff2b49a47b9b7534b2067b9\"\n" +{"status":true,"message":"DID registered successfully","result":null} ``` #### sample with invalid request (invalid did) ``` -curl -X POST http://localhost:8080/sign -d '{"did":"bafybmifqpi36mvzocqqpsh3rtjrjy5434wlqv4nz7zr4ejqx3qul5gl36q","sign_data":{"hash":"YmY0ZGI0NDEzNWZkYTg2Nzc1YTg1ZWQzMTRjZmIyZTI0MmVmZjBjYzdmOTI3OWNiYzVkZmQ5NjAxMTNkNDlhYQ==","id":"","mode":4}}' +curl -X POST http://localhost:8080/sign -d '{"did":"bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvanhb","sign_data":{"hash":"ZWQ1MWY0OWYxNTYzMTEzNGEzZTQyMDJmYWJkYmRjMzAzY2I3OGZlZjk1Zjc3MjhlM2M5NTllNGMxOWY5ZjFjZQ==","id":"BA81DDB1-5DBD-4C86-877B-1FA630A868D3","mode":4, "only_priv_key":true}}' ``` **Response:** ``` -{"error":"failed to send sign response, Invalid request ID"} +{"status":false,"message":"User not found, sql: no rows in result set","result":null} ``` @@ -225,19 +227,19 @@ curl -L -X POST http://localhost:8080/request_txn -H 'Authorization: Bearer &role=" -H 'Authorizati ``` #### sample with valid request ``` -curl -L -X GET "http://localhost:8080/get_all_ft?did=bafybmifebqlvq2uetxo3mgrwugf3k4rdjupo6h6fkn7mzrb5ekhxttamnq" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzU1NDIzMjksInN1YiI6ImJhZnlibWlmZWJxbHZxMnVldHhvM21ncnd1Z2YzazRyZGp1cG82aDZma243bXpyYjVla2h4dHRhbW5xIn0.Kii2kW5CTkdV7IjNjkaYiXTP40rYXlj7UcUWxmSxfm0' +curl -L -X GET "http://localhost:8080/get_all_ft?did=bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvaina" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3MjExODgsInN1YiI6ImJhZnlibWlheXN5YjVoYmRiNmNsc2s3am5jZGVqeHdvbXh1bXYzem9zNXQ1N2Y2Ynd6N251bXZhaW5hIn0.WU8P4UJiq-Jap_NhmHONhCah6d5xtoL6lHaH6ceUFJ4' ``` **Response:** ``` -{"ft_info":[{"creator_did":"bafybmifebqlvq2uetxo3mgrwugf3k4rdjupo6h6fkn7mzrb5ekhxttamnq","ft_count":2,"ft_name":"test1"}],"message":"Got FT info successfully","result":null,"status":true} +{"status":true,"message":"Got FT info successfully","result":[{"creator_did":"bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvaina","ft_count":4,"ft_name":"testFT-1"}]} ``` #### sample with invalid request (empty input to did) ``` -curl -L -X GET "http://localhost:8080/get_all_ft?did=" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzU1NDIzMjksInN1YiI6ImJhZnlibWlmZWJxbHZxMnVldHhvM21ncnd1Z2YzazRyZGp1cG82aDZma243bXpyYjVla2h4dHRhbW5xIn0.Kii2kW5CTkdV7IjNjkaYiXTP40rYXlj7UcUWxmSxfm0' +curl -L -X GET "http://localhost:8080/get_all_ft?did=" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3MjExODgsInN1YiI6ImJhZnlibWlheXN5YjVoYmRiNmNsc2s3am5jZGVqeHdvbXh1bXYzem9zNXQ1N2Y2Ynd6N251bXZhaW5hIn0.WU8P4UJiq-Jap_NhmHONhCah6d5xtoL6lHaH6ceUFJ4' ``` **Response:** ``` -{"error":"Missing required parameter: did"} +{"status":false,"message":"Missing required parameter: did","result":null} ``` ### Curl request to get FT chain @@ -362,19 +364,19 @@ curl -L -X GET "http://localhost:8080/get_ft_chain?did=&tokenID=&nft=" -H 'Aut ``` #### sample with valid request ``` -curl -L -X GET "http://localhost:8080/get_nft?did=bafybmifebqlvq2uetxo3mgrwugf3k4rdjupo6h6fkn7mzrb5ekhxttamnq&nft=Qme4NFXJ7f3f4umwbjL7A6ps2udw8WdcCz5cYWG2w9ecDA" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzU1NDIzMjksInN1YiI6ImJhZnlibWlmZWJxbHZxMnVldHhvM21ncnd1Z2YzazRyZGp1cG82aDZma243bXpyYjVla2h4dHRhbW5xIn0.Kii2kW5CTkdV7IjNjkaYiXTP40rYXlj7UcUWxmSxfm0' +curl -L -X GET "http://localhost:8080/get_nft?did=bafybmifqpi36mvzocqqpsh3rtjrjy5434wlqv4nz7zr4ejqx3qul5gl36q&nft=QmV8SEuVqrqhQxDsden9t22Hp7vyXUJCPLcS5ic6MnPK7P" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3ODc5NDQsInN1YiI6ImJhZnlibWlmcXBpMzZtdnpvY3FxcHNoM3J0anJqeTU0MzR3bHF2NG56N3pyNGVqcXgzcXVsNWdsMzZxIn0.yeC38PkFauWhOkOiWeyCAT-813O-KahTrr9ESZ8TF4Y' ``` **Response:** ``` -{"message":"NFT fetched successfully","result":null,"status":true} +{"status":true,"message":"NFT fetched successfully","result":null} ``` #### sample with invalid request (invalid did) ``` -curl -L -X GET "http://localhost:8080/get_nft?did=bafybmifebqlvq2uetxo3mgrwugf3k4rdjupo6h6fkn7mzrb5ekhxttamhj&nft=Qme4NFXJ7f3f4umwbjL7A6ps2udw8WdcCz5cYWG2w9echy" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzU1NDIzMjksInN1YiI6ImJhZnlibWlmZWJxbHZxMnVldHhvM21ncnd1Z2YzazRyZGp1cG82aDZma243bXpyYjVla2h4dHRhbW5xIn0.Kii2kW5CTkdV7IjNjkaYiXTP40rYXlj7UcUWxmSxfm0' +curl -L -X GET "http://localhost:8080/get_nft?did=bafybmifqpi36mvzocqqpsh3rtjrjy5434wlqv4nz7zr4ejqx3qul5glmnb&nft=QmV8SEuVqrqhQxDsden9t22Hp7vyXUJCPLcS5ic6MnPK7P" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3ODc5NDQsInN1YiI6ImJhZnlibWlmcXBpMzZtdnpvY3FxcHNoM3J0anJqeTU0MzR3bHF2NG56N3pyNGVqcXgzcXVsNWdsMzZxIn0.yeC38PkFauWhOkOiWeyCAT-813O-KahTrr9ESZ8TF4Y' ``` **Response:** ``` -{"error":"DID mismatch"} +{"status":false,"message":"DID mismatch","result":null} ``` ### Curl request to get NFT chain @@ -539,19 +541,19 @@ curl -L -X GET "http://localhost:8080/get_nft_chain?did=&nft=&la ``` #### sample with valid request ``` -curl -L -X GET "http://localhost:8080/get_nft_chain?did=bafybmifebqlvq2uetxo3mgrwugf3k4rdjupo6h6fkn7mzrb5ekhxttamnq&nft=Qme4NFXJ7f3f4umwbjL7A6ps2udw8WdcCz5cYWG2w9ecDA" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzU1NDIzMjksInN1YiI6ImJhZnlibWlmZWJxbHZxMnVldHhvM21ncnd1Z2YzazRyZGp1cG82aDZma243bXpyYjVla2h4dHRhbW5xIn0.Kii2kW5CTkdV7IjNjkaYiXTP40rYXlj7UcUWxmSxfm0' +curl -L -X GET "http://localhost:8080/get_nft_chain?did=bafybmifqpi36mvzocqqpsh3rtjrjy5434wlqv4nz7zr4ejqx3qul5gl36q&nft=QmV8SEuVqrqhQxDsden9t22Hp7vyXUJCPLcS5ic6MnPK7P" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3ODc5NDQsInN1YiI6ImJhZnlibWlmcXBpMzZtdnpvY3FxcHNoM3J0anJqeTU0MzR3bHF2NG56N3pyNGVqcXgzcXVsNWdsMzZxIn0.yeC38PkFauWhOkOiWeyCAT-813O-KahTrr9ESZ8TF4Y' ``` **Response:** ``` -{"NFTDataReply":[{"BlockId":"0-82227efb89892902326ccdda6422cd8a2247c037749fff6a5c181deaf6602936","BlockNo":0,"NFTData":"","NFTOwner":"bafybmifebqlvq2uetxo3mgrwugf3k4rdjupo6h6fkn7mzrb5ekhxttamnq","NFTValue":0},{"BlockId":"1-98baffa792c3bf87759ee19608c23f8c6afeb471f59f0a7911a971959ab7b81b","BlockNo":1,"NFTData":"","NFTOwner":"bafybmibuj72pm5x6yjhmfgacfusbk5veur5poqfm7qibk45kk5ktiep3d4","NFTValue":11}],"message":"Fetched NFT data","result":null,"status":true} +{"status":true,"message":"Fetched NFT data","result":[{"BlockId":"0-545c71dbbefd73709d8b13c4f6cd756d1a445898bdd823a9dd200a43d951c1a1","BlockNo":0,"NFTData":"","NFTOwner":"bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvaina","NFTValue":0},{"BlockId":"1-be986f46ca72891f0b046a16bd369051de168ef0581026175b7b7829bd8c36f6","BlockNo":1,"NFTData":"","NFTOwner":"bafybmifqpi36mvzocqqpsh3rtjrjy5434wlqv4nz7zr4ejqx3qul5gl36q","NFTValue":11}]} ``` #### sample with invalid request (invalid input to nft) ``` -curl -L -X GET "http://localhost:8080/get_nft_chain?did=bafybmifebqlvq2uetxo3mgrwugf3k4rdjupo6h6fkn7mzrb5ekhxttamnq&nft=Qme4NFXJ7f3f4umwbjL7A6ps2udw8WdcCz5cYWG2w9echj" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzU1NDIzMjksInN1YiI6ImJhZnlibWlmZWJxbHZxMnVldHhvM21ncnd1Z2YzazRyZGp1cG82aDZma243bXpyYjVla2h4dHRhbW5xIn0.Kii2kW5CTkdV7IjNjkaYiXTP40rYXlj7UcUWxmSxfm0' +curl -L -X GET "http://localhost:8080/get_nft_chain?did=bafybmifqpi36mvzocqqpsh3rtjrjy5434wlqv4nz7zr4ejqx3qul5gl36q&nft=QmV8SEuVqrqhQxDsden9t22Hp7vyXUJCPLcS5ic6MnPK7k" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3ODc5NDQsInN1YiI6ImJhZnlibWlmcXBpMzZtdnpvY3FxcHNoM3J0anJqeTU0MzR3bHF2NG56N3pyNGVqcXgzcXVsNWdsMzZxIn0.yeC38PkFauWhOkOiWeyCAT-813O-KahTrr9ESZ8TF4Y' ``` **Response:** ``` -{"NFTDataReply":null,"message":"Failed to get nft data, token does not exist","result":null,"status":false} +{"status":false,"message":"Failed to get nft data, token does not exist","result":null} ``` ### Curl request to get all NFTs @@ -561,17 +563,150 @@ curl -L -X GET "http://localhost:8080/get_all_nft?did=" -H 'Authorizatio ``` #### sample with valid request ``` -curl -L -X GET "http://localhost:8080/get_all_nft?did=bafybmifebqlvq2uetxo3mgrwugf3k4rdjupo6h6fkn7mzrb5ekhxttamnq" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzU1NDIzMjksInN1YiI6ImJhZnlibWlmZWJxbHZxMnVldHhvM21ncnd1Z2YzazRyZGp1cG82aDZma243bXpyYjVla2h4dHRhbW5xIn0.Kii2kW5CTkdV7IjNjkaYiXTP40rYXlj7UcUWxmSxfm0' +curl -L -X GET "http://localhost:8080/get_all_nft?did=bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvaina" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3MjExODgsInN1YiI6ImJhZnlibWlheXN5YjVoYmRiNmNsc2s3am5jZGVqeHdvbXh1bXYzem9zNXQ1N2Y2Ynd6N251bXZhaW5hIn0.WU8P4UJiq-Jap_NhmHONhCah6d5xtoL6lHaH6ceUFJ4' ``` **Response:** ``` -{"message":"Got All NFTs","nfts":[{"nft":"QmSYAeRRoxurxEpraDGu4B9fUn38VP7vXBoxzZqQnmfijY","nft_value":0,"owner_did":"bafybmifebqlvq2uetxo3mgrwugf3k4rdjupo6h6fkn7mzrb5ekhxttamnq"}],"result":null,"status":true} +{"status":true,"message":"Got All NFTs","result":[{"nft":"QmNMBaU9B6ZaBjaPgufTaTsTu9dHjtf3XWWogFPJ3zy9u6","nft_value":0,"owner_did":"bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvaina"}]} ``` #### sample with invalid request (invalid input to did) ``` -curl -L -X GET "http://localhost:8080/get_all_nft?did=bafybmifebqlvq2uetxo3mgrwugf3k4rdjupo6h6fkn7mzrb5ekhxttaghh" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzU1NDIzMjksInN1YiI6ImJhZnlibWlmZWJxbHZxMnVldHhvM21ncnd1Z2YzazRyZGp1cG82aDZma243bXpyYjVla2h4dHRhbW5xIn0.Kii2kW5CTkdV7IjNjkaYiXTP40rYXlj7UcUWxmSxfm0' +curl -L -X GET "http://localhost:8080/get_all_nft?did=bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvabhg" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3MjExODgsInN1YiI6ImJhZnlibWlheXN5YjVoYmRiNmNsc2s3am5jZGVqeHdvbXh1bXYzem9zNXQ1N2Y2Ynd6N251bXZhaW5hIn0.WU8P4UJiq-Jap_NhmHONhCah6d5xtoL6lHaH6ceUFJ4' +``` +**Response:** +``` +{"status":false,"message":"DID mismatch","result":null} +``` + +### Curl request to generate Smart Contract Token +``` +curl -L -X POST "http://localhost:8080/generate-smart-contract -H 'Authorization: Bearer ' -d '{"did":"", "binary_code_path":, "raw_code_path":"", "schema_file_path":"}' +``` +#### sample with valid request +``` +curl -L -X POST 'http://localhost:8080/generate-smart-contract' \ +-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3MjExODgsInN1YiI6ImJhZnlibWlheXN5YjVoYmRiNmNsc2s3am5jZGVqeHdvbXh1bXYzem9zNXQ1N2Y2Ynd6N251bXZhaW5hIn0.WU8P4UJiq-Jap_NhmHONhCah6d5xtoL6lHaH6ceUFJ4' \ +-F 'did=bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvaina' \ +-F 'binaryCodePath=@/home/maneesha/Rubix-Git/Smart-Contract/code_files/bidding_contract.wasm' \ +-F 'rawCodePath=@/home/maneesha/Rubix-Git/Smart-Contract/code_files/lib.rs' \ +-F 'schemaFilePath=@/home/maneesha/Rubix-Git/Smart-Contract/code_files/bidding_contract.json' + +``` +**Response:** +``` +{"status":true,"message":"Smart contract generated successfully","result":{"binaryFilePath":"uploads/36b74eed-d3af-435d-8b72-e618ee998bf9_binaryCodePath","rawFilePath":"uploads/36b74eed-d3af-435d-8b72-e618ee998bf9_rawCodePath","schemaFilePath":"uploads/36b74eed-d3af-435d-8b72-e618ee998bf9_schemaFilePath"}} +``` +#### sample with invalid request (invalid did) +``` +curl -L -X POST 'http://localhost:8080/generate-smart-contract' \ +-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3MjExODgsInN1YiI6ImJhZnlibWlheXN5YjVoYmRiNmNsc2s3am5jZGVqeHdvbXh1bXYzem9zNXQ1N2Y2Ynd6N251bXZhaW5hIn0.WU8P4UJiq-Jap_NhmHONhCah6d5xtoL6lHaH6ceUFJ4' \ +-F 'did=bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvanhb' \ +-F 'binaryCodePath=@/home/maneesha/Rubix-Git/Smart-Contract/code_files/bidding_contract.wasm' \ +-F 'rawCodePath=@/home/maneesha/Rubix-Git/Smart-Contract/code_files/lib.rs' \ +-F 'schemaFilePath=@/home/maneesha/Rubix-Git/Smart-Contract/code_files/bidding_contract.json' ``` **Response:** ``` -{"error":"DID mismatch"} +{"status":false,"message":"User not found, sql: no rows in result set","result":null} +``` + +### Curl request to deploy Smart Contract +``` +curl -L -X POST "http://localhost:8080/deploy-smart-contract -H 'Authorization: Bearer ' -d '{"deployerAddr":"", "smartContractToken":"", "quorumType":<1 or 2>, "rbtAmount":,"comment":""}' +``` +#### sample with valid request +``` +curl -L -X POST http://localhost:8080/deploy-smart-contract -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3MjExODgsInN1YiI6ImJhZnlibWlheXN5YjVoYmRiNmNsc2s3am5jZGVqeHdvbXh1bXYzem9zNXQ1N2Y2Ynd6N251bXZhaW5hIn0.WU8P4UJiq-Jap_NhmHONhCah6d5xtoL6lHaH6ceUFJ4' -d '{ + "deployerAddr":"bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvaina", + "smartContractToken":"QmWi85birn8KiNeVxRdH6mCWqVtimK2SUzecKhnKxgBt4H", + "quorumType":2, + "rbtAmount":3, + "comment":"testing sct deploy" +}' +``` +**Response:** +``` +{"status":true,"message":"Smart Contract Token Deployed successfully in 16.916829104s","result":null} +``` +#### sample with invalid request (invalid input to smartContractToken) +``` +curl -L -X POST http://localhost:8080/deploy-smart-contract -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3MjExODgsInN1YiI6ImJhZnlibWlheXN5YjVoYmRiNmNsc2s3am5jZGVqeHdvbXh1bXYzem9zNXQ1N2Y2Ynd6N251bXZhaW5hIn0.WU8P4UJiq-Jap_NhmHONhCah6d5xtoL6lHaH6ceUFJ4' -d '{ + "deployerAddr":"bafybmiaysyb5hbdb6clsk7jncdejxwomxumv3zos5t57f6bwz7numvaina", + "smartContractToken":"QmWi85birn8KiNeVxRdH6mCWqVtimK2SUzecKhnKxgH", + "quorumType":2, + "rbtAmount":3, + "comment":"testing sct deploy" +}' +``` +**Response:** +``` +{"status":false,"message":"smart contract deployment failed: Invalid smart contract token","result":null} +``` + +### Curl request to execute Smart Contract +``` +curl -L -X POST http://localhost:8080/execute-smart-contract -H 'Authorization: Bearer ' -d '{ + "comment": "string", + "smartContractToken": "string", + "smartContractData": "string", + "executorAddr": "string", + "quorumType": 0 +}' + +``` +#### sample with valid request +``` +curl -L -X POST http://localhost:8080/execute-smart-contract -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3ODc5NDQsInN1YiI6ImJhZnlibWlmcXBpMzZtdnpvY3FxcHNoM3J0anJqeTU0MzR3bHF2NG56N3pyNGVqcXgzcXVsNWdsMzZxIn0.yeC38PkFauWhOkOiWeyCAT-813O-KahTrr9ESZ8TF4Y' -d '{ + "comment": "testing nft transfer from wallet", + "smartContractToken": "QmWi85birn8KiNeVxRdH6mCWqVtimK2SUzecKhnKxgBt4H", + "smartContractData": "54", + "executorAddr": "bafybmifqpi36mvzocqqpsh3rtjrjy5434wlqv4nz7zr4ejqx3qul5gl36q", + "quorumType": 2 +}' +``` +**Response:** +``` +{"status":true,"message":"Smart Contract Token Executed successfully in 11.302358297s","result":null} +``` +#### sample with invalid request (invalid input format of quorumType) +``` +curl -L -X POST http://localhost:8080/execute-smart-contract -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3ODc5NDQsInN1YiI6ImJhZnlibWlmcXBpMzZtdnpvY3FxcHNoM3J0anJqeTU0MzR3bHF2NG56N3pyNGVqcXgzcXVsNWdsMzZxIn0.yeC38PkFauWhOkOiWeyCAT-813O-KahTrr9ESZ8TF4Y' -d '{ + "comment": "testing nft transfer from wallet", + "smartContractToken": "QmWi85birn8KiNeVxRdH6mCWqVtimK2SUzecKhnKxgBt4H", + "smartContractData": "54", + "executorAddr": "bafybmifqpi36mvzocqqpsh3rtjrjy5434wlqv4nz7zr4ejqx3qul5gl36q", + "quorumType": "2" +}' +``` +**Response:** +``` +{"status":false,"message":"Invalid input, json: cannot unmarshal string into Go struct field ExecuteSmartContractRequest.quorumType of type int","result":null} +``` + +### Curl request to subscribe Smart Contract +``` +curl -L -X POST "http://localhost:8080/subscribe-smart-contract -H 'Authorization: Bearer ' -d '{"did":"", "smartContractToken":}' + +``` +#### sample with valid request +``` +curl -L -X POST http://localhost:8080/subscribe-smart-contract -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3ODc5NDQsInN1YiI6ImJhZnlibWlmcXBpMzZtdnpvY3FxcHNoM3J0anJqeTU0MzR3bHF2NG56N3pyNGVqcXgzcXVsNWdsMzZxIn0.yeC38PkFauWhOkOiWeyCAT-813O-KahTrr9ESZ8TF4Y' -d '{ + "did":"bafybmifqpi36mvzocqqpsh3rtjrjy5434wlqv4nz7zr4ejqx3qul5gl36q", + "smartContractToken":"QmWi85birn8KiNeVxRdH6mCWqVtimK2SUzecKhnKxgBt4H" +}' +``` +**Response:** +``` +{"status":true,"message":"Smart contract subscribed successfully","result":null} +``` +#### sample with invalid request (invalid input to smartContractToken) +``` +curl -L -X POST http://localhost:8080/subscribe-smart-contract -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mzc3ODc5NDQsInN1YiI6ImJhZnlibWlmcXBpMzZtdnpvY3FxcHNoM3J0anJqeTU0MzR3bHF2NG56N3pyNGVqcXgzcXVsNWdsMzZxIn0.yeC38PkFauWhOkOiWeyCAT-813O-KahTrr9ESZ8TF4Y' -d '{ + "did":"bafybmifqpi36mvzocqqpsh3rtjrjy5434wlqv4nz7zr4ejqx3qul5gl36q", + "smartContractToken":"QmWi85birn8KiNeVxRdH6mCWqVtimK2SUzecKhnKxgH" +}' +``` +**Response:** ``` +{"status":false,"message":"failed to subscribe SmartContract, Invalid smart contract token","result":null} +``` \ No newline at end of file diff --git a/aesutils/aes.go b/aesutils/aes.go new file mode 100644 index 0000000..a8ecefd --- /dev/null +++ b/aesutils/aes.go @@ -0,0 +1,72 @@ +package aesutils + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/hex" + "fmt" +) + +// Encrypt the private key using AES-GCM +func EncryptPrivateKey(privateKey, secretKey string) (string, error) { + // Create an AES cipher + block, err := aes.NewCipher([]byte(secretKey)[:32]) + if err != nil { + fmt.Println("failed to create an aes cipher") + return "", err + } + + // Use AES-GCM for encryption + aesGCM, err := cipher.NewGCM(block) + if err != nil { + fmt.Println("failed to create aes gcm") + return "", err + } + + // Generate a random nonce + nonce := make([]byte, aesGCM.NonceSize()) + if _, err := rand.Read(nonce); err != nil { + fmt.Println("failed to create a random nonce") + return "", err + } + + // Encrypt the private key + ciphertext := aesGCM.Seal(nonce, nonce, []byte(privateKey), nil) + + // Return encrypted data as base64 + return hex.EncodeToString(ciphertext), nil +} + +// Decrypt the private key +func DecryptPrivateKey(encryptedKey, secretKey string) (string, error) { + ciphertext, err := hex.DecodeString(encryptedKey) + if err != nil { + return "", nil + } + + // Create an AES cipher + block, err := aes.NewCipher([]byte(secretKey)[:32]) + if err != nil { + return "", err + } + + // Use AES-GCM for decryption + aesGCM, err := cipher.NewGCM(block) + if err != nil { + return "", err + } + + // Since we know the ciphertext is actually nonce+ciphertext + // And len(nonce) == NonceSize(). We can separate the two. + nonceSize := aesGCM.NonceSize() + nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] + + // Decrypt the private key + plaintext, err := aesGCM.Open(nil, nonce, ciphertext, nil) + if err != nil { + return "", err + } + + return string(plaintext), nil +} diff --git a/aesutils/aes_test.go b/aesutils/aes_test.go new file mode 100644 index 0000000..2be6935 --- /dev/null +++ b/aesutils/aes_test.go @@ -0,0 +1,33 @@ +package aesutils + +import ( + "testing" + + "golang.org/x/crypto/bcrypt" +) + +func AESTest(t *testing.T, privateKey string, secretKey string) { + hashedSecretKey, err := bcrypt.GenerateFromPassword([]byte(secretKey), bcrypt.DefaultCost) + if err != nil { + t.Fatal("could not hash secret key, err", err) + } + + key := string(hashedSecretKey[:32]) + + encryptedPrivateKey, err := EncryptPrivateKey(privateKey, key) + if err != nil { + t.Fatal("failed to encrypt private key, err:", err) + } + decryptedPrivateKey, err := DecryptPrivateKey(encryptedPrivateKey, key) + if err != nil { + t.Fatal("failed to decrypt private key, err:", err) + } + if decryptedPrivateKey != privateKey { + t.Fatal("mismatched decrypted private key") + } +} + +func TestAES(t *testing.T) { + AESTest(t, "04b82f061b69471dc877ffc828687970da99fd2d65c6da7f08b9d9a793bf7262", "N1PCdw3M2B1TfJhoaY2mL736p2vCUc47") + AESTest(t, "randomstring", "abc123") +} diff --git a/docs/docs.go b/docs/docs.go index c498e18..fa299b0 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,5 +1,4 @@ -// Code generated by swaggo/swag. DO NOT EDIT. - +// Package docs Code generated by swaggo/swag. DO NOT EDIT package docs import "github.com/swaggo/swag" @@ -59,22 +58,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -166,22 +162,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -227,22 +220,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -344,22 +334,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -405,22 +392,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -473,22 +457,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -534,22 +515,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -621,22 +599,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -680,20 +655,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -737,20 +711,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -794,20 +767,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -851,20 +823,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -908,20 +879,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1056,22 +1026,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1117,22 +1084,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1176,20 +1140,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1235,20 +1198,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1294,22 +1256,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1348,19 +1307,77 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/main.SignRequest" + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" + } + } + } + } + }, + "/subscribe-smart-contract": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Subscribes a user to an SmartContract", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SmartContract" + ], + "summary": "Subscribe to an SmartContract", + "parameters": [ + { + "description": "SmartContract subscription details", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/main.SubscribeSmartContractRequest" + } + }, + { + "type": "string", + "description": "Authorization token (Bearer \u003cyour_token\u003e)", + "name": "Authorization", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.BasicResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/main.BasicResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1406,22 +1423,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1467,22 +1481,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1528,22 +1539,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1605,20 +1613,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1626,6 +1633,18 @@ const docTemplate = `{ } }, "definitions": { + "main.BasicResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "result": {}, + "status": { + "type": "boolean" + } + } + }, "main.CreateFTRequest": { "type": "object", "properties": { @@ -1722,7 +1741,7 @@ const docTemplate = `{ "quorumType": { "type": "integer" }, - "rbtamount": { + "rbtAmount": { "type": "integer" }, "smartContractToken": { @@ -1864,6 +1883,17 @@ const docTemplate = `{ } } }, + "main.SubscribeSmartContractRequest": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "smartContractToken": { + "type": "string" + } + } + }, "main.TokenResponse": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 092bf9b..5d2d7c3 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -52,22 +52,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -159,22 +156,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -220,22 +214,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -337,22 +328,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -398,22 +386,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -466,22 +451,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -527,22 +509,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -614,22 +593,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -673,20 +649,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -730,20 +705,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -787,20 +761,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -844,20 +817,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -901,20 +873,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1049,22 +1020,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1110,22 +1078,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1169,20 +1134,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1228,20 +1192,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1287,22 +1250,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1341,19 +1301,77 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/main.SignRequest" + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" + } + } + } + } + }, + "/subscribe-smart-contract": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Subscribes a user to an SmartContract", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SmartContract" + ], + "summary": "Subscribe to an SmartContract", + "parameters": [ + { + "description": "SmartContract subscription details", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/main.SubscribeSmartContractRequest" + } + }, + { + "type": "string", + "description": "Authorization token (Bearer \u003cyour_token\u003e)", + "name": "Authorization", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.BasicResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/main.BasicResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1399,22 +1417,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1460,22 +1475,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1521,22 +1533,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1598,20 +1607,19 @@ "200": { "description": "OK", "schema": { - "type": "object", - "additionalProperties": true + "$ref": "#/definitions/main.BasicResponse" } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } }, "401": { "description": "Unauthorized", "schema": { - "$ref": "#/definitions/main.ErrorResponse" + "$ref": "#/definitions/main.BasicResponse" } } } @@ -1619,6 +1627,18 @@ } }, "definitions": { + "main.BasicResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "result": {}, + "status": { + "type": "boolean" + } + } + }, "main.CreateFTRequest": { "type": "object", "properties": { @@ -1715,7 +1735,7 @@ "quorumType": { "type": "integer" }, - "rbtamount": { + "rbtAmount": { "type": "integer" }, "smartContractToken": { @@ -1857,6 +1877,17 @@ } } }, + "main.SubscribeSmartContractRequest": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "smartContractToken": { + "type": "string" + } + } + }, "main.TokenResponse": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index e6e735d..880a062 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,5 +1,13 @@ basePath: / definitions: + main.BasicResponse: + properties: + message: + type: string + result: {} + status: + type: boolean + type: object main.CreateFTRequest: properties: did: @@ -62,7 +70,7 @@ definitions: type: string quorumType: type: integer - rbtamount: + rbtAmount: type: integer smartContractToken: type: string @@ -155,6 +163,13 @@ definitions: nft: type: string type: object + main.SubscribeSmartContractRequest: + properties: + did: + type: string + smartContractToken: + type: string + type: object main.TokenResponse: properties: token: @@ -233,17 +248,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Add peer to a DID quorum @@ -302,17 +315,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Create fungible tokens @@ -341,17 +352,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Create a non-fungible token @@ -417,17 +426,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Deploy a smart contract @@ -456,17 +463,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Deploy an NFT @@ -500,17 +505,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Execute a smart contract @@ -539,17 +542,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Execute an NFT @@ -598,17 +599,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Generate a smart contract @@ -636,16 +635,15 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Get all fungible tokens @@ -673,16 +671,15 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Get all NFTs @@ -710,16 +707,15 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Get fungible token chain @@ -747,16 +743,15 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Get NFT details @@ -784,16 +779,15 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Get NFT chain @@ -879,17 +873,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Unpledge RBT tokens @@ -918,17 +910,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Register DID @@ -956,16 +946,15 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Get RBT balance @@ -994,16 +983,15 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Request a transaction @@ -1032,17 +1020,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Setup Quorum @@ -1066,20 +1052,57 @@ paths: "200": description: OK schema: - $ref: '#/definitions/main.SignRequest' + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Sign a transaction tags: - Txn + /subscribe-smart-contract: + post: + consumes: + - application/json + description: Subscribes a user to an SmartContract + parameters: + - description: SmartContract subscription details + in: body + name: request + required: true + schema: + $ref: '#/definitions/main.SubscribeSmartContractRequest' + - description: Authorization token (Bearer ) + in: header + name: Authorization + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/main.BasicResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/main.BasicResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/main.BasicResponse' + security: + - BearerAuth: [] + summary: Subscribe to an SmartContract + tags: + - SmartContract /subscribe_nft: post: consumes: @@ -1103,17 +1126,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Subscribe to an NFT @@ -1142,17 +1163,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Create test RBT tokens @@ -1181,17 +1200,15 @@ paths: "200": description: OK schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Transfer fungible tokens @@ -1231,16 +1248,15 @@ paths: "200": description: OK schema: - additionalProperties: true - type: object + $ref: '#/definitions/main.BasicResponse' "400": description: Bad Request schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' "401": description: Unauthorized schema: - $ref: '#/definitions/main.ErrorResponse' + $ref: '#/definitions/main.BasicResponse' security: - BearerAuth: [] summary: Get transactions by DID diff --git a/go.mod b/go.mod index 90482cb..90038c2 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,10 @@ -module github.com/gklps/wallet-frontend +module github.com/gklps/SafePass go 1.22.0 toolchain go1.23.3 -replace github.com/gklps/wallet-frontend/docs => ./docs +replace github.com/gklps/SafePass/docs => ./docs require ( github.com/gin-contrib/cors v1.7.2 @@ -17,14 +17,13 @@ require ( golang.org/x/crypto v0.32.0 ) -require github.com/google/uuid v1.6.0 // indirect +require github.com/google/uuid v1.6.0 require ( github.com/KyleBanks/depth v1.2.1 // indirect github.com/bytedance/sonic v1.12.7 // indirect github.com/bytedance/sonic/loader v0.2.2 // indirect github.com/cloudwego/base64x v0.1.4 // indirect - github.com/cloudwego/iasm v0.2.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gin-contrib/sse v1.0.0 // indirect diff --git a/main.go b/main.go index a4f0c63..5cd8234 100644 --- a/main.go +++ b/main.go @@ -24,8 +24,9 @@ import ( secp256k1 "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" - _ "github.com/gklps/wallet-frontend/docs" // Local Swagger docs import - "github.com/gklps/wallet-frontend/storage" + "github.com/gklps/SafePass/aesutils" + _ "github.com/gklps/SafePass/docs" // Local Swagger docs import + "github.com/gklps/SafePass/storage" "github.com/golang-jwt/jwt" "github.com/google/uuid" _ "github.com/mattn/go-sqlite3" // SQLite driver @@ -64,20 +65,23 @@ type ErrorResponse struct { // CreateUserRequest represents the structure for creating a new user type CreateUserRequest struct { - Email string `json:"email"` - Password string `json:"password"` - Name string `json:"name"` + Email string `json:"email"` + Password string `json:"password"` + Name string `json:"name"` + SecretKey string `json:"secret_key"` } // did request type DIDRequest struct { - Port int `json:"port"` + Port int `json:"port"` + SecretKey string `json:"secret_key"` } // sign request type SignRequest struct { - Data SignReqData `json:"sign_data"` - DID string `json:"did"` + Data SignReqData `json:"sign_data"` + DID string `json:"did"` + SecretKey string `json:"secret_key"` } type SignReqData struct { @@ -180,11 +184,11 @@ type ExecuteNFTRequest struct { } type DeploySmartContractRequest struct { - SmartContractToken string - DeployerAddr string - RBTAmount int - QuorumType int - Comment string + SmartContractToken string `json:"smartContractToken"` + DeployerAddr string `json:"deployerAddr"` + RBTAmount int `json:"rbtAmount"` + QuorumType int `json:"quorumType"` + Comment string `json:"comment"` } type GenerateSmartContractRequest struct { @@ -202,6 +206,19 @@ type ExecuteSmartContractRequest struct { SmartContractData string `json:"smartContractData" binding:"required"` } +// subscribe SmartContract request +type SubscribeSmartContractRequest struct { + DID string `json:"did"` + SmartContractToken string `json:"smartContractToken"` +} + +// general response by all handlers +type BasicResponse struct { + Status bool `json:"status"` + Message string `json:"message"` + Result interface{} `json:"result"` +} + // @title Wallet API Documentation // @version 1.0 // @description API documentation for the Wallet application. @@ -268,6 +285,7 @@ func main() { r.POST("/generate-smart-contract", generateSmartContractHandler) r.POST("/deploy-smart-contract", deploySmartContractHandler) r.POST("/execute-smart-contract", executeSmartContractHandler) + r.POST("/subscribe-smart-contract", subscribeSmartContractHandler) r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) @@ -307,10 +325,10 @@ func loginHandler(c *gin.Context) { } // Retrieve the hashed password and DID from the database for the user - var storedHashedPassword, did string + var storedHashedPassword, storedHashedSecretKey, did string var user User - row := db.QueryRow("SELECT id, email, name, password, did FROM walletUsers WHERE email = ?", creds.Email) - err := row.Scan(&user.ID, &user.Email, &user.Name, &storedHashedPassword, &did) + row := db.QueryRow("SELECT id, email, name, password, secret_key, did FROM walletUsers WHERE email = ?", creds.Email) + err := row.Scan(&user.ID, &user.Email, &user.Name, &storedHashedPassword, &storedHashedSecretKey, &did) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"}) return @@ -337,6 +355,7 @@ func loginHandler(c *gin.Context) { } c.JSON(http.StatusOK, gin.H{"token": tokenString}) + c.Writer.Write([]byte("\n")) } // CreateUser handler to create a new user and return the user profile @@ -364,6 +383,16 @@ func createUserHandler(c *gin.Context) { return } + // manage the secret key and hash it + if newUser.SecretKey == "" { + newUser.SecretKey = newUser.Password + } + hashedSecretKey, err := bcrypt.GenerateFromPassword([]byte(newUser.SecretKey), bcrypt.DefaultCost) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not hash secret key"}) + return + } + // Increment the port counter for each new user, until a running port is found var port int for { @@ -375,9 +404,17 @@ func createUserHandler(c *gin.Context) { } // Create the wallet and fetch the DID - walletRequest := `{"port":` + strconv.Itoa(port) + `}` - log.Printf("Sending request to /create_wallet: %s", walletRequest) - resp, err := http.Post("http://localhost:8080/create_wallet", "application/json", bytes.NewBuffer([]byte(walletRequest))) + data := DIDRequest{ + Port: port, + SecretKey: string(hashedSecretKey), // pass secret key to encrypt private key + } + walletRequest, err := json.Marshal(data) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error marshaling JSON, " + err.Error()}) + return + } + + resp, err := http.Post("http://localhost:8080/create_wallet", "application/json", bytes.NewBuffer(walletRequest)) if err != nil { log.Printf("HTTP request error: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not connect to wallet service"}) @@ -398,7 +435,6 @@ func createUserHandler(c *gin.Context) { c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not read wallet response"}) return } - log.Printf("Raw response from /create_wallet: %s", string(body)) if len(body) == 0 { log.Printf("Empty response from /create_wallet") c.JSON(http.StatusInternalServerError, gin.H{"error": "Empty response from wallet service"}) @@ -421,7 +457,7 @@ func createUserHandler(c *gin.Context) { } // Insert new user into the database with DID - _, err = db.Exec("INSERT INTO walletUsers (email, password, name, did) VALUES (?, ?, ?, ?)", newUser.Email, string(hashedPassword), newUser.Name, didResponse.DID) + _, err = db.Exec("INSERT INTO walletUsers (email, password, secret_key, name, did) VALUES (?, ?, ?, ?, ?)", newUser.Email, string(hashedPassword), string(hashedSecretKey), newUser.Name, didResponse.DID) if err != nil { log.Printf("Database insert error: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not create user"}) @@ -434,6 +470,7 @@ func createUserHandler(c *gin.Context) { "name": newUser.Name, "did": didResponse.DID, }) + c.Writer.Write([]byte("\n")) } // Middleware to authenticate the user via JWT @@ -596,7 +633,7 @@ func VerifyToken(tokenString string, publicKey *ecdsa.PublicKey) (bool, jwt.MapC // @Tags DID // @Accept json // @Produce json -// @Param request body DIDRequest true "Port for DID request" +// @Param request body DIDRequest true "Port for DID request and secret key" // @Success 200 {object} map[string]string // @Failure 400 {object} ErrorResponse // @Failure 500 {object} ErrorResponse @@ -627,9 +664,17 @@ func createWalletHandler(c *gin.Context) { return } - // Save user to database + // encrypt private key to store privKeyStr := hex.EncodeToString(privateKey.Serialize()) - err = storage.InsertUser(did, pubKeyStr, privKeyStr, mnemonic, req.Port) + encryptedPrivateKey, err := aesutils.EncryptPrivateKey(privKeyStr, req.SecretKey) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to encrypt private key, " + err.Error()}) + c.Writer.Write([]byte("\n")) + return + } + + // Save user to database + err = storage.InsertUser(did, pubKeyStr, encryptedPrivateKey, mnemonic, req.Port) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to store user data, " + err.Error()}) // Add a newline to the response body @@ -649,16 +694,21 @@ func createWalletHandler(c *gin.Context) { // @Accept json // @Produce json // @Param request body ReqToRubixNode true "DID" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /register_did [post] func registerDIDHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -673,7 +723,9 @@ func registerDIDHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -682,20 +734,25 @@ func registerDIDHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } - // Optionally, verify the DID exists in the database + // verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found" + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } var req ReqToRubixNode if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input" + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return @@ -703,36 +760,45 @@ func registerDIDHandler(c *gin.Context) { // Ensure the DID from the token matches the one in the request body if req.DID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } - // // Initialize or retrieve an existing channel for the DID - // didChannel, _ := getOrCreateDIDChannel(did) - response, err := registerDIDRequest(did, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return } - respMsg, err := callSignHandler(response, did) - if err != nil { - log.Println("failed to call sign handler, err:", err.Error()) - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + respMsg := response["message"].(string) + // sign, if the message says 'signature needed' + if strings.Contains(respMsg, "Signature needed") { + respMsg, err = callSignHandler(response, did) + if err != nil { + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) + return + } + } else { + basicResponse.Status = response["status"].(bool) + basicResponse.Message = respMsg + c.JSON(http.StatusInternalServerError, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return } - c.JSON(http.StatusOK, respMsg) + // prepare response + basicResponse.Status = true + basicResponse.Message = respMsg + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -743,16 +809,21 @@ func registerDIDHandler(c *gin.Context) { // @Accept json // @Produce json // @Param request body ReqToRubixNode true "DID" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /setup_quorum [post] func setupQuorumHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -767,7 +838,9 @@ func setupQuorumHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -776,20 +849,25 @@ func setupQuorumHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } var req ReqToRubixNode if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input" + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return @@ -797,21 +875,25 @@ func setupQuorumHandler(c *gin.Context) { // Ensure the DID from the token matches the one in the request body if req.DID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } resp, err := setupQuorumRequest(req.DID, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - c.JSON(http.StatusOK, resp) + // prepare response + basicResponse.Status = true + basicResponse.Message = resp + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -873,16 +955,21 @@ func setupQuorumRequest(did string, rubixNodePort string) (string, error) { // @Accept json // @Produce json // @Param request body DIDPeerMap true "Peer details" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /add_peer [post] func addPeerHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -897,7 +984,9 @@ func addPeerHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -906,20 +995,25 @@ func addPeerHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } var req DIDPeerMap if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return @@ -927,21 +1021,25 @@ func addPeerHandler(c *gin.Context) { // Ensure the DID from the token matches the one in the request body if req.SelfDID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } resp, err := addPeerRequest(req, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - c.JSON(http.StatusOK, resp) + // prepare response + basicResponse.Status = true + basicResponse.Message = resp + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -999,41 +1097,81 @@ func addPeerRequest(data DIDPeerMap, rubixNodePort string) (string, error) { // @Accept json // @Produce json // @Param request body SignRequest true "Transaction signing request" -// @Success 200 {object} SignResponse -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Router /sign [post] func signTransactionHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } var req SignRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Decode the Base64 string back to the byte array decodedBytes, err := base64.StdEncoding.DecodeString(req.Data.Hash) if err != nil { - fmt.Println("Error decoding Base64 string:", err) + basicResponse.Message = "Error decoding Base64 string, " + err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } - log.Println("2-decoded bytes:", decodedBytes) user, err := storage.GetUserByDID(req.DID) if err != nil { - c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusNotFound, basicResponse) + c.Writer.Write([]byte("\n")) + return + } + + // Retrieve the hashed secret key from the database for the user + var storedHashedSecretKey string + var userInfo User + row := db.QueryRow("SELECT id, secret_key FROM walletUsers WHERE did = ?", user.DID) + err = row.Scan(&userInfo.ID, &storedHashedSecretKey) + if err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "failed to get secret key of user"}) + return + } + + // decrypt the encrypted private key + decryptedPrivateKey, err := aesutils.DecryptPrivateKey(user.PrivateKey, storedHashedSecretKey) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to decrypt private key, " + err.Error()}) + c.Writer.Write([]byte("\n")) + return + } + + // Decode private key + privKeyBytes, err := hex.DecodeString(decryptedPrivateKey) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to decode private key, " + err.Error()}) + c.Writer.Write([]byte("\n")) return } - signature, err := signData(user.PrivateKey.ToECDSA(), decodedBytes) + privateKey := secp256k1.PrivKeyFromBytes(privKeyBytes) + + signature, err := signData(privateKey.ToECDSA(), decodedBytes) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to sign data"}) + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } // Verify signature if !verifySignature(user.PublicKey, decodedBytes, signature) { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Signature verification failed"}) + basicResponse.Message = "Signature verification failed" + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } @@ -1047,11 +1185,17 @@ func signTransactionHandler(c *gin.Context) { } resp, err := signResponse(signResp, user.Port) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } - c.JSON(http.StatusOK, resp) + // prepare response + basicResponse.Status = resp["status"].(bool) + basicResponse.Message = resp["message"].(string) + basicResponse.Result = resp["result"] + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -1063,13 +1207,6 @@ func callSignHandler(response map[string]interface{}, did string) (string, error id := respResult["id"].(string) mode := respResult["mode"].(float64) - // Decode the Base64 string back to the byte array - decodedBytes, err := base64.StdEncoding.DecodeString(hashStr) - if err != nil { - fmt.Println("Error decoding Base64 string:", err) - } - log.Println("1-decoded bytes:", decodedBytes) - // prepare sign request signReq := SignRequest{ DID: did, @@ -1088,7 +1225,6 @@ func callSignHandler(response map[string]interface{}, did string) (string, error return "", err } - // log.Printf("Sending request to /create_wallet: %s", walletRequest) resp, err := http.Post("http://localhost:8080/sign", "application/json", bytes.NewBuffer(bodyJSON)) if err != nil { log.Printf("HTTP request error: %v", err) @@ -1107,7 +1243,7 @@ func callSignHandler(response map[string]interface{}, did string) (string, error log.Printf("Error reading response body: %v", err) return "", err } - log.Printf("Raw response from /sign: %s", string(body)) + if len(body) == 0 { return "", fmt.Errorf("empty response from /sign") } @@ -1136,16 +1272,21 @@ func callSignHandler(response map[string]interface{}, did string) (string, error // @Accept json // @Produce json // @Param request body TxnRequest true "Transaction details" -// @Success 200 {object} map[string]interface{} -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /request_txn [post] func requestTransactionHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -1160,7 +1301,9 @@ func requestTransactionHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -1169,53 +1312,79 @@ func requestTransactionHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } var req TxnRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if req.DID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } jwtToken, err := GenerateJWT(req.DID, req.ReceiverDID, req.RBTAmount) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate JWT"}) + basicResponse.Message = "Failed to generate JWT, " + err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } isValid, claims, err := VerifyToken(jwtToken, user.PublicKey.ToECDSA()) if !isValid { - c.JSON(http.StatusUnauthorized, gin.H{"error": err}) + basicResponse.Message = err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } - log.Println("Token claims:", claims) - result := SendAuthRequest(jwtToken, strconv.Itoa(user.Port)) + response := SendAuthRequest(jwtToken, strconv.Itoa(user.Port)) - // sign response - respMsg, err := callSignHandler(result, did) + respMsg := response["message"].(string) + // sign, if the message says 'signature needed' + if strings.Contains(respMsg, "Signature needed") { + respMsg, err = callSignHandler(response, did) + if err != nil { + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) + return + } + } else { + basicResponse.Status = response["status"].(bool) + basicResponse.Message = respMsg + c.JSON(http.StatusInternalServerError, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) + return + } - c.JSON(http.StatusOK, gin.H{ - "did": req.DID, - "jwt": jwtToken, - "status": respMsg, - }) + // prepare response + basicResponse.Status = true + basicResponse.Message = respMsg + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -1226,16 +1395,21 @@ func requestTransactionHandler(c *gin.Context) { // @Accept json // @Produce json // @Param did query string true "DID of the user" -// @Success 200 {object} map[string]interface{} -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /request_balance [get] func requestBalanceHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -1250,7 +1424,9 @@ func requestBalanceHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -1259,40 +1435,52 @@ func requestBalanceHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found" + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } userDID := c.Query("did") if userDID == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Missing required parameter: did"}) + basicResponse.Message = "Missing required parameter: did" + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if userDID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } result, err := RequestBalance(did, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err}) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return } - c.JSON(http.StatusOK, result) + // prepare response + basicResponse.Status = result["status"].(bool) + basicResponse.Message = result["message"].(string) + basicResponse.Result = result["account_info"] + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -1303,16 +1491,21 @@ func requestBalanceHandler(c *gin.Context) { // @Accept json // @Produce json // @Param request body GenerateTestRBTRequest true "Request to generate test RBTs" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /testrbt/create [post] func createTestRBTHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -1327,7 +1520,9 @@ func createTestRBTHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -1336,21 +1531,25 @@ func createTestRBTHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } var req GenerateTestRBTRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return @@ -1358,25 +1557,45 @@ func createTestRBTHandler(c *gin.Context) { // Ensure the DID from the token matches the one in the request body if req.DID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } - resp, err := GenerateTestRBT(req, strconv.Itoa(user.Port)) + response, err := GenerateTestRBT(req, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - log.Println("response body:", resp) - // sign response - respMsg, err := callSignHandler(resp, did) + respMsg := response["message"].(string) + // sign, if the message says 'signature needed' + if strings.Contains(respMsg, "Signature needed") { + respMsg, err = callSignHandler(response, did) + if err != nil { + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) + return + } + } else { + basicResponse.Status = response["status"].(bool) + basicResponse.Message = respMsg + c.JSON(http.StatusInternalServerError, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) + return + } - c.JSON(http.StatusOK, respMsg) + // prepare response + basicResponse.Status = true + basicResponse.Message = respMsg + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -1390,16 +1609,21 @@ func createTestRBTHandler(c *gin.Context) { // @Param role query string false "Role in the transaction (e.g., sender, receiver)" // @Param startDate query string false "Start date for filtering transactions" // @Param endDate query string false "End date for filtering transactions" -// @Success 200 {object} map[string]interface{} -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /txn/by_did [get] func getTxnByDIDHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -1414,7 +1638,9 @@ func getTxnByDIDHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -1423,14 +1649,17 @@ func getTxnByDIDHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User nopt found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } @@ -1438,13 +1667,16 @@ func getTxnByDIDHandler(c *gin.Context) { userDID := c.Query("did") if userDID == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Missing required parameter: did \n"}) + basicResponse.Message = "Missing required parameter: did" + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if userDID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } @@ -1455,13 +1687,18 @@ func getTxnByDIDHandler(c *gin.Context) { result, err := RequestTxnsByDID(did, role, startDate, endDate, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err}) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return } - c.JSON(http.StatusOK, result) + // prepare response + basicResponse.Status = result["status"].(bool) + basicResponse.Message = result["message"].(string) + basicResponse.Result = result["TxnDetails"] + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -1525,7 +1762,6 @@ func didRequest(pubKeyStr string, rubixNodePort string) (string, error) { // SendAuthRequest sends a JWT authentication request to the Rubix node func SendAuthRequest(jwtToken string, rubixNodePort string) map[string]interface{} { - log.Println("sending auth request to rubix node...") authURL := fmt.Sprintf("http://localhost:%s/api/send-jwt-from-wallet", rubixNodePort) req, err := http.NewRequest("POST", authURL, nil) if err != nil { @@ -1553,7 +1789,6 @@ func SendAuthRequest(jwtToken string, rubixNodePort string) map[string]interface return nil } - fmt.Printf("Response from Rubix Node: %s\n", body) // Process the data as needed var response map[string]interface{} err = json.Unmarshal(body, &response) @@ -1792,8 +2027,6 @@ func registerDIDRequest(did string, rubixNodePort string) (map[string]interface{ return nil, err } - fmt.Println("response data after unmarshal : ", response) - respMsg := response["message"].(string) respStatus := response["status"].(bool) @@ -1810,16 +2043,21 @@ func registerDIDRequest(did string, rubixNodePort string) (map[string]interface{ // @Accept json // @Produce json // @Param request body ReqToRubixNode true "Request to unpledge RBTs" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /rbt/unpledge [post] func unpledgeRBTHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -1834,7 +2072,9 @@ func unpledgeRBTHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -1843,21 +2083,25 @@ func unpledgeRBTHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } var req ReqToRubixNode if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return @@ -1865,21 +2109,25 @@ func unpledgeRBTHandler(c *gin.Context) { // Ensure the DID from the token matches the one in the request body if req.DID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } resp, err := unpledgeRBTRequest(req, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - c.JSON(http.StatusOK, resp) + // prepare response + basicResponse.Status = true + basicResponse.Message = resp + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -1939,16 +2187,21 @@ func unpledgeRBTRequest(data ReqToRubixNode, rubixNodePort string) (string, erro // @Accept json // @Produce json // @Param request body CreateFTRequest true "Fungible token creation details" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /create_ft [post] func createFTHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -1963,7 +2216,9 @@ func createFTHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -1972,52 +2227,70 @@ func createFTHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } var req CreateFTRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if req.DID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } response, err := createFTReq(req, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - respMsg, err := callSignHandler(response, did) - if err != nil { - log.Println("failed to call sign handler, err:", err.Error()) - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + respMsg := response["message"].(string) + // sign, if the message says 'signature needed' + if strings.Contains(respMsg, "Signature needed") { + respMsg, err = callSignHandler(response, did) + if err != nil { + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) + return + } + } else { + basicResponse.Status = response["status"].(bool) + basicResponse.Message = respMsg + c.JSON(http.StatusInternalServerError, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return } - c.JSON(http.StatusOK, respMsg) + // prepare response + basicResponse.Status = true + basicResponse.Message = respMsg + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -2076,16 +2349,21 @@ func createFTReq(data CreateFTRequest, rubixNodePort string) (map[string]interfa // @Accept json // @Produce json // @Param request body TransferFTReq true "Fungible token transfer details" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /transfer_ft [post] func transferFTHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2100,7 +2378,9 @@ func transferFTHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2109,53 +2389,70 @@ func transferFTHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } var req TransferFTReq if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if req.Sender != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } - resp, err := transferFTRequest(req, strconv.Itoa(user.Port)) + response, err := transferFTRequest(req, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - // sign response - respMsg, err := callSignHandler(resp, did) - if err != nil { - log.Println("failed to call sign handler, err:", err.Error()) - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + respMsg := response["message"].(string) + // sign, if the message says 'signature needed' + if strings.Contains(respMsg, "Signature needed") { + respMsg, err = callSignHandler(response, did) + if err != nil { + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) + return + } + } else { + basicResponse.Status = response["status"].(bool) + basicResponse.Message = respMsg + c.JSON(http.StatusInternalServerError, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return } - c.JSON(http.StatusOK, respMsg) + // prepare response + basicResponse.Status = true + basicResponse.Message = respMsg + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -2214,16 +2511,21 @@ func transferFTRequest(data TransferFTReq, rubixNodePort string) (map[string]int // @Accept json // @Produce json // @Param did query string true "DID of the user" -// @Success 200 {object} map[string]interface{} -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /get_all_ft [get] func getAllFTHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2238,7 +2540,9 @@ func getAllFTHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2247,14 +2551,17 @@ func getAllFTHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } @@ -2262,27 +2569,33 @@ func getAllFTHandler(c *gin.Context) { userDID := c.Query("did") if userDID == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Missing required parameter: did"}) + basicResponse.Message = "Missing required parameter: did" + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if userDID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } resp, err := getAllFTRequest(did, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } - c.JSON(http.StatusOK, resp) + // prepare response + basicResponse.Status = resp["status"].(bool) + basicResponse.Message = resp["message"].(string) + basicResponse.Result = resp["ft_info"] + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -2327,16 +2640,21 @@ func getAllFTRequest(did string, rubixNodePort string) (map[string]interface{}, // @Accept json // @Produce json // @Param tokenID query string true "Token ID" -// @Success 200 {object} map[string]interface{} -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /get_ft_chain [get] func getFTChainHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2351,7 +2669,9 @@ func getFTChainHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2360,14 +2680,17 @@ func getFTChainHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } @@ -2375,12 +2698,15 @@ func getFTChainHandler(c *gin.Context) { userDID := c.Query("did") if userDID == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Missing required parameter: did"}) + basicResponse.Message = "Missing required parameter: did" + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if userDID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } @@ -2388,20 +2714,25 @@ func getFTChainHandler(c *gin.Context) { tokenID := c.Query("tokenID") if tokenID == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Missing required parameter: tokenID"}) + basicResponse.Message = "Missing required parameter: tokenID" + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } resp, err := getFTChainRequest(tokenID, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } - c.JSON(http.StatusOK, resp) + //prepare response + basicResponse.Status = resp["status"].(bool) + basicResponse.Message = resp["message"].(string) + basicResponse.Result = resp["TokenChainData"] + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -2448,16 +2779,21 @@ func getFTChainRequest(tokenID string, rubixNodePort string) (map[string]interfa // @Accept json // @Produce json // @Param request body CreateNFTRequest true "NFT creation details" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /create_nft [post] func createNFTHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2472,7 +2808,9 @@ func createNFTHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2481,40 +2819,49 @@ func createNFTHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } var req CreateNFTRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if req.DID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } resp, err := createNFTReq(req, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - c.JSON(http.StatusOK, resp) + // prepare response + basicResponse.Status = true + basicResponse.Message = resp + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -2625,16 +2972,21 @@ func createNFTReq(data CreateNFTRequest, rubixNodePort string) (string, error) { // @Accept json // @Produce json // @Param request body SubscribeNFTRequest true "NFT subscription details" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /subscribe_nft [post] func subscribeNFTHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2649,7 +3001,9 @@ func subscribeNFTHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2658,41 +3012,50 @@ func subscribeNFTHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } var req SubscribeNFTRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if req.DID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } resp, err := subscribeNFTRequest(req.NFT, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - c.JSON(http.StatusOK, resp) + // preapre response + basicResponse.Status = true + basicResponse.Message = resp + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -2753,16 +3116,21 @@ func subscribeNFTRequest(nft string, rubixNodePort string) (string, error) { // @Accept json // @Produce json // @Param request body DeployNFTRequest true "NFT deployment details" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /deploy_nft [post] func deployNFTHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2777,7 +3145,9 @@ func deployNFTHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2786,53 +3156,70 @@ func deployNFTHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } var req DeployNFTRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if req.DID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } - resp, err := deployNFTRequest(req, strconv.Itoa(user.Port)) + response, err := deployNFTRequest(req, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - // sign response - respMsg, err := callSignHandler(resp, did) - if err != nil { - log.Println("failed to call sign handler, err:", err.Error()) - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + respMsg := response["message"].(string) + // sign, if the message says 'signature needed' + if strings.Contains(respMsg, "Signature needed") { + respMsg, err = callSignHandler(response, did) + if err != nil { + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) + return + } + } else { + basicResponse.Status = response["status"].(bool) + basicResponse.Message = respMsg + c.JSON(http.StatusInternalServerError, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return } - c.JSON(http.StatusOK, respMsg) + // prepare response + basicResponse.Status = true + basicResponse.Message = respMsg + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -2891,16 +3278,21 @@ func deployNFTRequest(data DeployNFTRequest, rubixNodePort string) (map[string]i // @Accept json // @Produce json // @Param request body ExecuteNFTRequest true "NFT execution details" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /execute_nft [post] func executeNFTHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2915,7 +3307,9 @@ func executeNFTHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -2924,53 +3318,70 @@ func executeNFTHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } var req ExecuteNFTRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if req.DID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } - resp, err := executeNFTRequest(req, strconv.Itoa(user.Port)) + response, err := executeNFTRequest(req, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - // sign response - respMsg, err := callSignHandler(resp, did) - if err != nil { - log.Println("failed to call sign handler, err:", err.Error()) - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + respMsg := response["message"].(string) + // sign, if the message says 'signature needed' + if strings.Contains(respMsg, "Signature needed") { + respMsg, err = callSignHandler(response, did) + if err != nil { + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) + return + } + } else { + basicResponse.Status = response["status"].(bool) + basicResponse.Message = respMsg + c.JSON(http.StatusInternalServerError, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return } - c.JSON(http.StatusOK, respMsg) + // prepare response + basicResponse.Status = true + basicResponse.Message = respMsg + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -3029,16 +3440,21 @@ func executeNFTRequest(data ExecuteNFTRequest, rubixNodePort string) (map[string // @Accept json // @Produce json // @Param nft query string true "NFT ID" -// @Success 200 {object} map[string]interface{} -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /get_nft [get] func getNFTHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -3053,7 +3469,9 @@ func getNFTHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -3062,14 +3480,17 @@ func getNFTHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } @@ -3077,13 +3498,16 @@ func getNFTHandler(c *gin.Context) { userDID := c.Query("did") if userDID == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Missing required parameter: did"}) + basicResponse.Message = "Missing required parameter: did" + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if userDID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } @@ -3091,20 +3515,26 @@ func getNFTHandler(c *gin.Context) { nft := c.Query("nft") if nft == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Missing required parameter: did"}) + basicResponse.Message = "Missing required parameter: nft" + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } resp, err := getNFTRequest(nft, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - c.JSON(http.StatusOK, resp) + // prepare response + basicResponse.Status = resp["status"].(bool) + basicResponse.Message = resp["message"].(string) + basicResponse.Result = resp["result"] + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -3149,16 +3579,21 @@ func getNFTRequest(nft string, rubixNodePort string) (map[string]interface{}, er // @Accept json // @Produce json // @Param nft query string true "NFT ID" -// @Success 200 {object} map[string]interface{} -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /get_nft_chain [get] func getNFTChainHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -3173,7 +3608,9 @@ func getNFTChainHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -3182,14 +3619,17 @@ func getNFTChainHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } @@ -3197,13 +3637,16 @@ func getNFTChainHandler(c *gin.Context) { userDID := c.Query("did") if userDID == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Missing required parameter: did"}) + basicResponse.Message = "Missing required parameter: did" + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if userDID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } @@ -3211,7 +3654,9 @@ func getNFTChainHandler(c *gin.Context) { nft := c.Query("nft") if nft == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Missing required parameter: tokenID"}) + basicResponse.Message = "Missing required parameter: tokenID" + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } @@ -3219,14 +3664,18 @@ func getNFTChainHandler(c *gin.Context) { resp, err := getNFTChainRequest(nft, latest, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - c.JSON(http.StatusOK, resp) + //prepare response + basicResponse.Status = resp["status"].(bool) + basicResponse.Message = resp["message"].(string) + basicResponse.Result = resp["NFTDataReply"] + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -3271,16 +3720,21 @@ func getNFTChainRequest(nft string, latest string, rubixNodePort string) (map[st // @Accept json // @Produce json // @Param did query string true "DID of the user" -// @Success 200 {object} map[string]interface{} -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /get_all_nft [get] func getAllNFTHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -3295,7 +3749,9 @@ func getAllNFTHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -3304,14 +3760,17 @@ func getAllNFTHandler(c *gin.Context) { claims := token.Claims.(jwt.MapClaims) did, ok := claims["sub"].(string) if !ok { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: missing or invalid DID"}) + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) return } // Optionally, verify the DID exists in the database user, err := storage.GetUserByDID(did) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } @@ -3319,27 +3778,34 @@ func getAllNFTHandler(c *gin.Context) { userDID := c.Query("did") if userDID == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Missing required parameter: did"}) + basicResponse.Message = "Missing required parameter: did" + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Ensure the DID from the token matches the one in the request body if userDID != did { - c.JSON(http.StatusForbidden, gin.H{"error": "DID mismatch"}) + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) c.Writer.Write([]byte("\n")) return } resp, err := getAllNFTRequest(did, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) + return } - c.JSON(http.StatusOK, resp) + // prepare response + basicResponse.Status = resp["status"].(bool) + basicResponse.Message = resp["message"].(string) + basicResponse.Result = resp["nfts"] + c.JSON(http.StatusOK, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) } @@ -3386,16 +3852,21 @@ func getAllNFTRequest(did string, rubixNodePort string) (map[string]interface{}, // @Produce json // @Param rubixNodePort query string true "Rubix node port" // @Param request body DeploySmartContractRequest true "Smart contract deployment details" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /deploy-smart-contract [post] func deploySmartContractHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -3410,43 +3881,69 @@ func deploySmartContractHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } - rubixNodePort := c.Query("rubixNodePort") - if rubixNodePort == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Rubix node port is required"}) - return - } + // rubixNodePort := c.Query("rubixNodePort") + // if rubixNodePort == "" { + // basicResponse.Message = "Rubix node port is required" + // c.JSON(http.StatusBadRequest, basicResponse) + // c.Writer.Write([]byte("\n")) + // return + // } var req DeploySmartContractRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } - resp, err := deploySmartContractReq(req, rubixNodePort) + user, err := storage.GetUserByDID(req.DeployerAddr) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } - // sign response - respMsg, err := callSignHandler(resp, req.DeployerAddr) + response, err := deploySmartContractReq(req, strconv.Itoa(user.Port)) if err != nil { - log.Println("failed to call sign handler, err:", err.Error()) - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) + return + } + + respMsg := response["message"].(string) + // sign, if the message says 'signature needed' + if strings.Contains(respMsg, "Signature needed") { + respMsg, err = callSignHandler(response, req.DeployerAddr) + if err != nil { + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) + return + } + } else { + basicResponse.Status = response["status"].(bool) + basicResponse.Message = respMsg + c.JSON(http.StatusInternalServerError, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return } - c.JSON(http.StatusOK, respMsg) + //prepare response + basicResponse.Status = true + basicResponse.Message = respMsg + c.JSON(http.StatusOK, basicResponse) c.Writer.Write([]byte("\n")) } @@ -3508,16 +4005,21 @@ func deploySmartContractReq(data DeploySmartContractRequest, rubixNodePort strin // @Param binaryCodePath formData file true "Binary code file" // @Param rawCodePath formData file true "Raw code file" // @Param schemaFilePath formData file true "Schema file" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /generate-smart-contract [post] func generateSmartContractHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -3532,41 +4034,45 @@ func generateSmartContractHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } - rubixNodePort := c.Query("rubixNodePort") - if rubixNodePort == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Rubix node port is required"}) - return - } - err = c.Request.ParseMultipartForm(10 << 20) // Limit to 10 MB if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Unable to parse form data"}) + basicResponse.Message = "Unable to parse form data, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } // Save the files to the server's file system binaryFile, _, err := c.Request.FormFile("binaryCodePath") if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Error reading binary file"}) + basicResponse.Message = "Error reading binary file, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } defer binaryFile.Close() rawFile, _, err := c.Request.FormFile("rawCodePath") if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Error reading raw file"}) + basicResponse.Message = "Error reading raw file" + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } defer rawFile.Close() schemaFile, _, err := c.Request.FormFile("schemaFilePath") if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Error reading schema file"}) + basicResponse.Message = "Error reading schema file" + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } defer schemaFile.Close() @@ -3583,37 +4089,49 @@ func generateSmartContractHandler(c *gin.Context) { binaryOut, err := os.Create(binaryFilePath) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Error saving binary file"}) + basicResponse.Message = "Error saving baniry file" + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } defer binaryOut.Close() _, err = io.Copy(binaryOut, binaryFile) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Error saving binary file"}) + basicResponse.Message = "Error saving binary file" + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } rawOut, err := os.Create(rawFilePath) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Error saving raw file"}) + basicResponse.Message = "Error saving raw file" + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } defer rawOut.Close() _, err = io.Copy(rawOut, rawFile) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Error saving raw file"}) + basicResponse.Message = "Error saving raw file" + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } schemaOut, err := os.Create(schemaFilePath) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Error saving schema file"}) + basicResponse.Message = "Error saving schema file" + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } defer schemaOut.Close() _, err = io.Copy(schemaOut, schemaFile) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Error saving schema file"}) + basicResponse.Message = "Error saving schema file" + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } @@ -3625,20 +4143,34 @@ func generateSmartContractHandler(c *gin.Context) { SchemaFilePath: schemaFilePath, } + // get user details by did + user, err := storage.GetUserByDID(data.DID) + if err != nil { + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) + return + } + // Trigger Rubix Node call - respMsg, err := generateSmartContractReq(data, rubixNodePort) + respMsg, err := generateSmartContractReq(data, strconv.Itoa(user.Port)) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Error generating smart contract"}) + basicResponse.Message = "Error generating smart contract" + c.JSON(http.StatusInternalServerError, basicResponse) + c.Writer.Write([]byte("\n")) return } // Respond with the paths or stream the files back to the client - c.JSON(http.StatusOK, gin.H{ - "message": respMsg, // This will be the response from Rubix node + basicResponse.Status = true + basicResponse.Message = respMsg // This will be the response from Rubix node + basicResponse.Result = map[string]interface{}{ "binaryFilePath": binaryFilePath, "rawFilePath": rawFilePath, "schemaFilePath": schemaFilePath, - }) + } + c.JSON(http.StatusOK, basicResponse) + c.Writer.Write([]byte("\n")) // Stream the files back to the client (if required) // c.File(binaryFilePath) // Example of sending the binary file back @@ -3772,16 +4304,21 @@ func generateSmartContractReq(data GenerateSmartContractRequest, rubixNodePort s // @Produce json // @Param rubixNodePort query string true "Rubix node port" // @Param request body ExecuteSmartContractRequest true "Smart contract execution details" -// @Success 200 {object} map[string]string -// @Failure 400 {object} ErrorResponse -// @Failure 401 {object} ErrorResponse +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse // @Security BearerAuth // @Param Authorization header string true "Authorization token (Bearer )" // @Router /execute-smart-contract [post] func executeSmartContractHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } tokenString := c.GetHeader("Authorization") if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Token is required"}) + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } @@ -3796,43 +4333,62 @@ func executeSmartContractHandler(c *gin.Context) { }) if err != nil || !token.Valid { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) c.Abort() return } - rubixNodePort := c.Query("rubixNodePort") - if rubixNodePort == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Rubix node port is required"}) - return - } - var req ExecuteSmartContractRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) return } - resp, err := executeSmartContractReq(req, rubixNodePort) + // get user info by did + user, err := storage.GetUserByDID(req.ExecutorAddr) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) c.Writer.Write([]byte("\n")) return } - // sign response - respMsg, err := callSignHandler(resp, req.ExecutorAddr) + response, err := executeSmartContractReq(req, strconv.Itoa(user.Port)) if err != nil { - log.Println("failed to call sign handler, err:", err.Error()) - c.JSON(http.StatusBadRequest, gin.H{ - "error": err.Error(), - }) + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) + return + } + + respMsg := response["message"].(string) + // sign, if the message says 'signature needed' + if strings.Contains(respMsg, "Signature needed") { + respMsg, err = callSignHandler(response, req.ExecutorAddr) + if err != nil { + basicResponse.Message = err.Error() + c.JSON(http.StatusInternalServerError, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) + return + } + } else { + basicResponse.Status = response["status"].(bool) + basicResponse.Message = respMsg + c.JSON(http.StatusInternalServerError, basicResponse) // Add a newline to the response body if required c.Writer.Write([]byte("\n")) return } - c.JSON(http.StatusOK, respMsg) + // prepare response + basicResponse.Status = true + basicResponse.Message = respMsg + c.JSON(http.StatusOK, basicResponse) c.Writer.Write([]byte("\n")) } @@ -3883,3 +4439,147 @@ func executeSmartContractReq(data ExecuteSmartContractRequest, rubixNodePort str return response, nil } + +// @Summary Subscribe to an SmartContract +// @Description Subscribes a user to an SmartContract +// @Tags SmartContract +// @Accept json +// @Produce json +// @Param request body SubscribeSmartContractRequest true "SmartContract subscription details" +// @Success 200 {object} BasicResponse +// @Failure 400 {object} BasicResponse +// @Failure 401 {object} BasicResponse +// @Security BearerAuth +// @Param Authorization header string true "Authorization token (Bearer )" +// @Router /subscribe-smart-contract [post] +func subscribeSmartContractHandler(c *gin.Context) { + basicResponse := BasicResponse{ + Status: false, + } + tokenString := c.GetHeader("Authorization") + if tokenString == "" { + basicResponse.Message = "Token is required" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) + c.Abort() + return + } + + tokenString = tokenString[len("Bearer "):] + + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("Unexpected signing method") + } + return jwtSecret, nil + }) + + if err != nil || !token.Valid { + basicResponse.Message = "Invalid token, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) + c.Abort() + return + } + + // Extract the DID claim from the token + claims := token.Claims.(jwt.MapClaims) + did, ok := claims["sub"].(string) + if !ok { + basicResponse.Message = "Invalid token: missing or invalid DID" + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) + return + } + + // Optionally, verify the DID exists in the database + user, err := storage.GetUserByDID(did) + if err != nil { + basicResponse.Message = "User not found, " + err.Error() + c.JSON(http.StatusUnauthorized, basicResponse) + c.Writer.Write([]byte("\n")) + return + } + + var req SubscribeSmartContractRequest + if err := c.ShouldBindJSON(&req); err != nil { + basicResponse.Message = "Invalid input, " + err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + c.Writer.Write([]byte("\n")) + return + } + + // Ensure the DID from the token matches the one in the request body + if req.DID != did { + basicResponse.Message = "DID mismatch" + c.JSON(http.StatusForbidden, basicResponse) + c.Writer.Write([]byte("\n")) + return + } + + resp, err := subscribeSmartContractRequest(req.SmartContractToken, strconv.Itoa(user.Port)) + if err != nil { + basicResponse.Message = err.Error() + c.JSON(http.StatusBadRequest, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) + return + } + + // preapre response + basicResponse.Status = true + basicResponse.Message = resp + c.JSON(http.StatusOK, basicResponse) + // Add a newline to the response body if required + c.Writer.Write([]byte("\n")) +} + +// subscribeSmartContractRequest sends request to subscribe SmartContract +func subscribeSmartContractRequest(SmartContract string, rubixNodePort string) (string, error) { + data := map[string]interface{}{ + "smartContractToken": SmartContract, + } + bodyJSON, err := json.Marshal(data) + if err != nil { + fmt.Println("Error marshaling JSON:", err) + return "", err + } + + url := fmt.Sprintf("http://localhost:%s/api/subscribe-smart-contract", rubixNodePort) + req, err := http.NewRequest("POST", url, bytes.NewBuffer(bodyJSON)) + if err != nil { + fmt.Println("Error creating HTTP request:", err) + return "", err + } + + req.Header.Set("Content-Type", "application/json; charset=UTF-8") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + fmt.Println("Error sending HTTP request:", err) + return "", err + } + defer resp.Body.Close() + data2, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Printf("Error reading response body: %s\n", err) + return "", err + } + + // Process the data as needed + var response map[string]interface{} + err = json.Unmarshal(data2, &response) + if err != nil { + fmt.Println("Error unmarshaling response:", err) + } + + respMsg := response["message"].(string) + respStatus := response["status"].(bool) + + if !respStatus { + return "", fmt.Errorf("failed to subscribe SmartContract, %s", respMsg) + } + + return respMsg, nil +} diff --git a/storage/storage.go b/storage/storage.go index 9521a71..4c6e425 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -1,7 +1,9 @@ package storage import ( + "crypto/rand" "database/sql" + "encoding/base64" "encoding/hex" "fmt" "log" @@ -13,7 +15,7 @@ import ( type User struct { DID string // IPFS hash (simulated) PublicKey *secp256k1.PublicKey - PrivateKey *secp256k1.PrivateKey + PrivateKey string // ChildPath int Mnemonic string Port int @@ -22,10 +24,100 @@ type User struct { // sqlite database: manages tables for user data and jwt tokens var db *sql.DB +// EnsureTableColumns ensures the required columns exist in the given table +func EnsureTableColumns(tableName string, requiredColumns map[string]string) error { + query := fmt.Sprintf("PRAGMA table_info(%s);", tableName) + rows, err := db.Query(query) + if err != nil { + return fmt.Errorf("failed to get table info for %s: %v", tableName, err) + } + defer rows.Close() + + existingColumns := make(map[string]bool) + var name, columnType string + var cid, notnull, pk int + var dfltValue sql.NullString + + for rows.Next() { + if err := rows.Scan(&cid, &name, &columnType, ¬null, &dfltValue, &pk); err != nil { + return fmt.Errorf("error scanning table info for %s: %v", tableName, err) + } + existingColumns[name] = true + } + + for column, colType := range requiredColumns { + if !existingColumns[column] { + alterQuery := fmt.Sprintf("ALTER TABLE %s ADD COLUMN %s %s;", tableName, column, colType) + _, err := db.Exec(alterQuery) + if err != nil { + return fmt.Errorf("failed to add column %s to table %s: %v", column, tableName, err) + } + log.Printf("Added missing column %s to table %s", column, tableName) + } + } + return nil +} + +// GenerateSecretKey generates a random base64-encoded secret key +func GenerateSecretKey() (string, error) { + bytes := make([]byte, 32) + _, err := rand.Read(bytes) + if err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(bytes), nil +} + +// UpdateWalletUsersSecretKeys ensures all walletUsers have a secret_key +func UpdateWalletUsersSecretKeys() error { + tx, err := db.Begin() + if err != nil { + return fmt.Errorf("failed to start transaction: %v", err) + } + rows, err := tx.Query("SELECT id FROM walletUsers WHERE secret_key IS NULL OR secret_key = ''") + if err != nil { + tx.Rollback() + return fmt.Errorf("failed to fetch walletUsers without secret_key: %v", err) + } + defer rows.Close() + + stmt, err := tx.Prepare("UPDATE walletUsers SET secret_key = ? WHERE id = ?") + if err != nil { + tx.Rollback() + return fmt.Errorf("failed to prepare update statement: %v", err) + } + defer stmt.Close() + + var id int + for rows.Next() { + if err := rows.Scan(&id); err != nil { + tx.Rollback() + return fmt.Errorf("error scanning walletUsers: %v", err) + } + secretKey, err := GenerateSecretKey() + if err != nil { + tx.Rollback() + return fmt.Errorf("failed to generate secret key: %v", err) + } + _, err = tx.Exec("UPDATE walletUsers SET secret_key = ? WHERE id = ?", secretKey, id) + if err != nil { + tx.Rollback() + return fmt.Errorf("failed to update secret_key for walletUser %d: %v", id, err) + } + log.Printf("Updated secret_key for walletUser %d", id) + } + + if err := tx.Commit(); err != nil { + return fmt.Errorf("failed to commit transaction: %v", err) + } + + return nil +} + // initiate database func InitDatabase() (*sql.DB, error) { var err error - db, err = sql.Open("sqlite3", "./wallet.db") + db, err = sql.Open("sqlite3", "./wallet.db?_journal_mode=WAL&cache_size=-200000&temp_store=MEMORY&locking_mode=EXCLUSIVE") if err != nil { log.Fatal("Failed to connect to database:", err) } @@ -54,6 +146,7 @@ func InitDatabase() (*sql.DB, error) { id INTEGER PRIMARY KEY, email TEXT, password TEXT, + secret_key TEXT, name TEXT, did TEXT ) @@ -64,6 +157,21 @@ func InitDatabase() (*sql.DB, error) { log.Fatal("Failed to create tables:", err) } + err = EnsureTableColumns("walletUsers", map[string]string{ + "secret_key": "TEXT", + }) + if err != nil { + log.Fatal("Failed to ensure walletUsers columns:", err) + } + + // Update missing secret_keys + err = UpdateWalletUsersSecretKeys() + if err != nil { + log.Fatal("Failed to update walletUsers secret keys:", err) + } + // Optimize database performance + db.Exec("PRAGMA analyze;") + db.Exec("PRAGMA vacuum;") return db, nil } @@ -71,8 +179,6 @@ func InitDatabase() (*sql.DB, error) { func InsertUser(did, publicKey, privateKey, mnemonic string, port int) error { if db == nil { log.Println("Database connection is nil") - } else { - log.Println("Database connection initialized successfully") } query := `INSERT INTO users (did, public_key, private_key, mnemonic, port) VALUES (?, ?, ?, ?, ?)` @@ -84,8 +190,6 @@ func InsertUser(did, publicKey, privateKey, mnemonic string, port int) error { func GetUserByDID(did string) (*User, error) { if db == nil { log.Println("Database connection is nil") - } else { - log.Println("Database connection initialized successfully") } query := `SELECT public_key, private_key, mnemonic, port FROM users WHERE did = ?` @@ -109,18 +213,10 @@ func GetUserByDID(did string) (*User, error) { return nil, fmt.Errorf("failed to parse public key: %v", err) } - // Decode private key - privKeyBytes, err := hex.DecodeString(privateKey) - if err != nil { - return nil, fmt.Errorf("failed to decode private key: %v", err) - } - - privKey := secp256k1.PrivKeyFromBytes(privKeyBytes) - return &User{ DID: did, PublicKey: pubKey, - PrivateKey: privKey, + PrivateKey: privateKey, Mnemonic: mnemonic, Port: port, }, nil diff --git a/wallet.db b/wallet.db deleted file mode 100644 index 20200c2..0000000 Binary files a/wallet.db and /dev/null differ