1
0

cashid.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. const CashID = require('cashid')
  2. const PouchDB = require('pouchdb')
  3. const uuidv4 = require('uuid/v4')
  4. const moment = require('moment')
  5. // const superagent = require('superagent')
  6. /* Initialize slack. */
  7. const slack = require('./slack')
  8. /* Initialize CashID. */
  9. // const cashid = new CashID()
  10. const cashid = new CashID('api.apecs.dev', '/v1/cashid')
  11. /* Add Mango queries to PouchDB. */
  12. PouchDB.plugin(require('pouchdb-find'))
  13. /* Initialize databases. */
  14. const dbProfiles = new PouchDB('http://api:password@localhost:5984/profiles')
  15. const dbDetails = new PouchDB('http://api:password@localhost:5984/profiles_details')
  16. const dbSessions = new PouchDB('http://api:password@localhost:5984/apecs_sessions')
  17. /**
  18. * Add New Profile
  19. */
  20. const addNewProfile = async function (_address, _cashAccounts) {
  21. /* Initialize address. */
  22. let address = null
  23. /* Normalize address. */
  24. if (_address.includes('bitcoincash:')) {
  25. address = _address.slice(12)
  26. } else {
  27. address = _address
  28. }
  29. /* Set (mango) query. */
  30. const query = {
  31. selector: {
  32. 'account.type': 'bch',
  33. 'account.address': address,
  34. },
  35. // sort: [{'index':'asc'}]
  36. }
  37. /* Request data. */
  38. const result = await dbProfiles.find(query)
  39. console.log('ACCOUNT SEARCH', _address, _cashAccounts, result)
  40. /* Validate results. */
  41. if (!result || !result.docs || !result.docs.length > 0) {
  42. /* Initialize response. */
  43. let response = null
  44. /* Set profile id. */
  45. const profileid = uuidv4()
  46. /* Set account. */
  47. const account = {
  48. type: 'bch',
  49. address,
  50. }
  51. /* Set addresses. */
  52. const addresses = {
  53. bch: address
  54. }
  55. /* Initialize cash accounts. */
  56. let cashAccounts = null
  57. /* Validate cash accounts. */
  58. if (_cashAccounts.length > 0) {
  59. cashAccounts = _cashAccounts
  60. }
  61. /* Build new profile. */
  62. const profile = {
  63. _id: profileid,
  64. account,
  65. createdAt: moment().valueOf()
  66. }
  67. console.log('NEW PROFILE', profile)
  68. response = await dbProfiles.put(profile)
  69. .catch(err => console.error('NEW PROFILE ERROR:', err))
  70. console.log('ADD PROFILE RESPONSE', response)
  71. /* Build new profile details. */
  72. const details = {
  73. _id: profileid,
  74. addresses,
  75. cashAccounts,
  76. createdAt: moment().valueOf()
  77. }
  78. console.log('NEW PROFILE DETAILS', details)
  79. response = await dbDetails.put(details)
  80. .catch(err => console.error('NEW PROFILE DETAILS ERROR:', err))
  81. console.log('ADD PROFILE DETAIL RESPONSE', response)
  82. /* Send slack notification. */
  83. slack({
  84. profile,
  85. details,
  86. })
  87. } else {
  88. /* Send slack notification. */
  89. slack({
  90. _address,
  91. _cashAccounts,
  92. })
  93. }
  94. }
  95. /**
  96. * Projects
  97. */
  98. const projects = async function (req, res) {
  99. // console.log('REQUEST', req)
  100. /* Set id. */
  101. // const baseCurrency = req.params.baseCurrency
  102. // const quoteCurrency = req.params.quoteCurrency
  103. // const symbol = req.query.symbol
  104. // console.log('BASE CURRENCY', baseCurrency)
  105. // console.log('QUOTE CURRENCY', quoteCurrency)
  106. /* Set headers. */
  107. // const headers = req.headers
  108. // console.log('HEADERS', headers)
  109. /* Set body. */
  110. const body = req.body
  111. // console.log('\nBODY', body)
  112. /* Validate request body. */
  113. const validation = cashid.validateRequest(body)
  114. // console.log('\nVALIDATION', validation)
  115. /* Parse request. */
  116. // const parsed = cashid.parseCashIDRequest(body.request)
  117. // console.log('\nPARSED', parsed)
  118. // TODO: We MUST validate the timestamp to within 30 seconds
  119. // either before or after our server time (check clock)
  120. if (validation && validation.address) {
  121. // console.log('VALIDATION SUCCESS', validation.address, body.address)
  122. /* Set session id. */
  123. const sessionId = uuidv4()
  124. // console.log('SESSION ID', sessionId)
  125. /* Set address. */
  126. const address = validation.address
  127. // console.log('ADDRESS', address)
  128. /* Set signature. */
  129. const signature = validation.signature
  130. // console.log('SIGNATURE', signature)
  131. /* Set data. */
  132. const data = validation.data
  133. // console.log('DATA', data)
  134. /* Validate address. */
  135. if (address !== body.address) {
  136. return res.json({
  137. error: 'Address DOES NOT match.',
  138. statuscode: 131
  139. })
  140. }
  141. /* Validate signature. */
  142. if (signature !== body.signature) {
  143. return res.json({
  144. error: 'Signature DOES NOT match.',
  145. statuscode: 131
  146. })
  147. }
  148. /* Validate data. */
  149. if (data !== body.data) {
  150. return res.json({
  151. error: 'Data DOES NOT match.',
  152. statuscode: 131
  153. })
  154. }
  155. /* Set CashID buffer. */
  156. const cidBuf = Buffer.from(body.request)
  157. // console.log('CASHID REQUEST BUFFER', cidBuf)
  158. /* Set CashID (authorization) hash. */
  159. // const authHash = bitbox.Crypto.sha256(cidBuf).toString('hex')
  160. // console.log('CASHID AUTH HASH', authHash)
  161. /* Initialize cash account(s). */
  162. let cashAccounts = []
  163. // const reverseLookup = await bitbox.CashAccounts
  164. // .reverseLookup(address)
  165. // .catch(err => console.error('REVERSE LOOKUP ERROR:', err))
  166. // console.log('REVERSE LOOKUP', reverseLookup)
  167. /* Validate lookup. */
  168. if (reverseLookup && reverseLookup.results) {
  169. reverseLookup.results.forEach(account => {
  170. /* Add cash account info. */
  171. cashAccounts.push({
  172. accountEmoji: account.accountEmoji,
  173. nameText: account.nameText,
  174. accountNumber: account.accountNumber,
  175. })
  176. })
  177. }
  178. /* Add new profile. */
  179. addNewProfile(address, cashAccounts)
  180. /* Initialize response. */
  181. let response = null
  182. /* Set active flag. */
  183. const isActive = true
  184. /* Set creation date. */
  185. const createdAt = moment().valueOf()
  186. /* Set last update. */
  187. const updatedAt = moment().valueOf()
  188. try {
  189. response = await dbSessions.put({
  190. _id: sessionId,
  191. authHash,
  192. validation,
  193. cashAccounts,
  194. isActive,
  195. createdAt,
  196. updatedAt
  197. })
  198. console.log('DB RESPONSE', response)
  199. } catch (err) {
  200. console.log('DB ERROR:', err)
  201. }
  202. // FIXME: Perform more validation
  203. return res.json({
  204. statuscode: 0
  205. // 'status': 0
  206. })
  207. } else {
  208. console.log('VALIDATION FAILED!')
  209. // FIXME: Parse the actual status code
  210. // `Request domain api.apecs.dev is invalid, this service uses auth.cashid.org, statuscode:131`
  211. /* Set status code. */
  212. // res.status(131)
  213. return res.json({
  214. statuscode: 131
  215. // 'status': 1
  216. // 'status': 131
  217. })
  218. }
  219. }
  220. module.exports = projects