OSDN Git Service

Merge: merge pro
[bytom/Byone.git] / src / background.js
1 import { LocalStream } from 'extension-streams'
2 import InternalMessage from '@/messages/internal'
3 import * as MsgTypes from './messages/types'
4 import NotificationService from './services/NotificationService'
5 import StorageService from './services/StorageService'
6 import Prompt from './prompts/Prompt';
7 import * as PromptTypes from './prompts/PromptTypes'
8 import migrate from './migrations/migrator'
9
10 import _ from 'lodash'
11 import Error from './utils/errors/Error'
12 import { BTM, camelize } from './utils/constants'
13
14 import account from "@/models/account";
15
16 let prompt = null;
17 let lockTime = null;
18
19 export default class Background {
20   constructor() {
21     this.setupInternalMessaging()
22   }
23
24   setupInternalMessaging() {
25     LocalStream.watch((request, sendResponse) => {
26       console.log(request)
27       const message = InternalMessage.fromJson(request)
28       this.dispatchMessage(sendResponse, message)
29     })
30   }
31
32   dispatchMessage(sendResponse, message) {
33     switch (message.type) {
34       case MsgTypes.SETCHAIN:
35         Background.setChain(sendResponse, message.payload)
36         break
37       case MsgTypes.TRANSFER:
38         this.transfer(sendResponse, message.payload)
39         break
40       case MsgTypes.ADVTRANSFER:
41         this.advancedTransfer(sendResponse, message.payload)
42         break
43       case MsgTypes.SEND:
44         this.send(sendResponse, message.payload)
45         break
46       case MsgTypes.SIGNTRANSACTION:
47         this.signTransaction(sendResponse, message.payload)
48         break
49       case MsgTypes.SIGNMESSAGE:
50         this.signMessage(sendResponse, message.payload)
51         break
52       case MsgTypes.REQUEST_CURRENT_ACCOUNT:
53         this.requestCurrentAccount(sendResponse, message.payload)
54         break
55       case MsgTypes.REQUEST_CURRENT_NETWORK:
56         this.requestCurrentNetwork(sendResponse)
57         break
58       case MsgTypes.REQUEST_CURRENT_CHAIN_TYPE:
59         this.requestCurrentChain(sendResponse)
60         break
61       case MsgTypes.ENABLE:
62         Background.authenticate(sendResponse, message.payload)
63         break
64       case MsgTypes.DISABLE:
65         Background.disauthenticate(sendResponse, message.payload)
66         break
67       case MsgTypes.SET_PROMPT:
68         Background.setPrompt(sendResponse, message.payload);
69         break;
70       case MsgTypes.GET_PROMPT:
71         Background.getPrompt(sendResponse);
72         break;
73       case MsgTypes.LOAD:
74         Background.load(sendResponse);
75         break;
76       case MsgTypes.UPDATE:
77         Background.update(sendResponse, message.payload);
78         break;
79     }
80   }
81
82   static setPrompt(sendResponse, notification){
83     prompt = notification;
84     sendResponse(true);
85   }
86
87   static getPrompt(sendResponse){
88     sendResponse(prompt);
89   }
90
91   signMessage(sendResponse, payload) {
92     var requestBody = payload.value
93
94     if(requestBody.address === undefined){
95       sendResponse(Error.typeMissed('address'));
96       return false;
97     }
98     if(requestBody.message === undefined){
99       sendResponse(Error.typeMissed('message'));
100       return false;
101     }
102
103     const {domain} = payload;
104     const data={
105       value: requestBody,
106       type:  'message'
107     }
108
109     NotificationService.open(new Prompt(PromptTypes.REQUEST_PROMPT, domain, data ,approved => {
110       sendResponse(camelize(approved));
111     }));
112   }
113
114   transfer(sendResponse, payload) {
115     var requestBody = payload.value
116
117     if(requestBody.from === undefined){
118       sendResponse(Error.typeMissed('from'));
119       return false;
120     }
121     if(requestBody.to === undefined){
122       sendResponse(Error.typeMissed('to'));
123       return false;
124     }
125     if(requestBody.asset === undefined){
126       sendResponse(Error.typeMissed('asset'));
127       return false;
128     }
129
130     const {domain} = payload;
131     const data={
132       value: requestBody,
133       type:  'transfer'
134     }
135
136     NotificationService.open(new Prompt(PromptTypes.REQUEST_PROMPT, domain, data ,approved => {
137       sendResponse(camelize(approved));
138     }));
139   }
140
141   advancedTransfer(sendResponse, payload) {
142     var requestBody = payload.value
143
144     if(requestBody.input === undefined){
145       sendResponse(Error.typeMissed('input'));
146       return false;
147     }
148     if(requestBody.output === undefined){
149       sendResponse(Error.typeMissed('output'));
150       return false;
151     }
152     if(requestBody.gas === undefined){
153       sendResponse(Error.typeMissed('gas'));
154       return false;
155     }
156
157     const {domain} = payload;
158
159     const data={
160       value: requestBody,
161       type:  'advTransfer'
162     }
163
164     NotificationService.open(new Prompt(PromptTypes.REQUEST_PROMPT, domain, data ,approved => {
165       sendResponse(camelize(approved));
166     }));
167
168   }
169
170   signTransaction(sendResponse, payload) {
171     const {domain,  value} = payload;
172
173     const data={
174       value: value,
175       type:  'signTransaction'
176     }
177
178     NotificationService.open(new Prompt(PromptTypes.REQUEST_PROMPT, domain, data ,approved => {
179       sendResponse(camelize(approved));
180     }));
181   }
182
183   requestCurrentAccount(sendResponse, payload){
184     Background.load(bytom => {
185       const domain = payload.domain;
186       if(bytom.settings.domains.find(_domain => _domain === domain)) {
187         const currentAccount =  bytom.currentAccount
188         const {vpAddress, address} = currentAccount
189         const classicAddress = currentAccount.bytom1.address
190         const isClassic = bytom.settings.netType === 'bytom1'
191         let account = {
192           addresses: [vpAddress, isClassic?classicAddress:address],
193           rootXPub: currentAccount.xpub
194         }
195         if(bytom.settings.netType === 'vapor'){
196           account.address = vpAddress;
197         }else if(bytom.settings.netType === 'bytom1'){
198           account.address = classicAddress;
199         }else{
200           account.address = address;
201         }
202
203         sendResponse(account)
204       } else{
205         sendResponse(null);
206         return false;
207       }
208     })
209
210   }
211
212   requestCurrentNetwork(sendResponse){
213     Background.load(bytom => {
214         sendResponse(bytom.settings.network);
215     })
216   }
217
218   requestCurrentChain(sendResponse){
219     Background.load(bytom => {
220       const chain = bytom.settings.netType ==='vapor'?'vapor':bytom.settings.netType==='bytom'?'bytom':bytom.settings.netType
221       sendResponse(chain);
222     })
223   }
224
225   send(sendResponse, payload) {
226     const action = payload.action
227     if(action){
228       let promise
229       switch (action){
230         case 'listAllAccount':
231           promise = accountAction.list()
232           break
233       }
234       if(promise){
235         promise.then(resp =>
236         {
237           sendResponse(resp)
238         })
239       }
240     }
241   }
242
243   /***
244    * Returns the saved instance of Bytom from the storage
245    * @param sendResponse - Delegating response handler
246    * @returns {Bytom}
247    */
248   static load(sendResponse){
249     StorageService.get().then(async bytom => {
250
251       const migrated = await migrate(bytom);
252       if(migrated) this.update(() => {}, bytom);
253       sendResponse(bytom)
254     })
255   }
256
257   /***
258    * Updates the Scatter instance inside persistent storage
259    * @param sendResponse - Delegating response handler
260    * @param bytom - The updated cleartext Scatter instance
261    * @returns {boolean}
262    */
263   static update(sendResponse, bytom){
264     StorageService.save(bytom).then(saved => {
265       sendResponse(bytom)
266     })
267   }
268
269   static setChain(sendResponse, newNetType) {
270     Background.load(bytom => {
271       const currentNet = bytom.settings.netType
272
273       if( newNetType !== currentNet){
274         bytom.settings.netType = newNetType;
275         this.update(() => sendResponse({status:'success'}), bytom);
276       }else{
277         sendResponse(Error.duplicate(newNetType));
278       }
279     })
280   }
281
282   static authenticate(sendResponse, payload){
283     Background.load(bytom => {
284       const {domain,  ...domainAttrs} = payload;
285
286       const currentAccount =  bytom.currentAccount
287
288       if(!currentAccount){
289         sendResponse(Error.signatureAccountMissing())
290       }else{
291         const {vpAddress, address} = currentAccount
292         const classicAddress = currentAccount.bytom1.address
293         const isClassic = bytom.settings.netType === 'bytom1'
294
295         let account = {
296           // for bytom1
297           addresses: [vpAddress, isClassic? classicAddress: address],
298           rootXPub: currentAccount.xpub,
299           // for bytom2
300           xpub: currentAccount.xpub,
301           net: bytom.settings.network,
302           chain: bytom.settings.netType
303         }
304         if(bytom.settings.netType === 'vapor'){
305           account.address = vpAddress;
306           account.account = vpAddress
307         }else if(bytom.settings.netType === 'bytom1'){
308           account.address = classicAddress;
309           account.account = classicAddress
310         }else{
311           account.address = address;
312           account.account = address
313         }
314
315
316         if(bytom.settings.domains.find(_domain => _domain === domain)) {
317           sendResponse(account);
318         } else{
319           NotificationService.open(new Prompt(PromptTypes.REQUEST_AUTH, payload.domain, payload, approved => {
320             if (approved === false) sendResponse(Error.forbidden())
321             else if(approved.hasOwnProperty('isError')) sendResponse(approved);
322             else {
323               bytom.settings.domains.unshift(domain);
324               bytom.settings.domainsMeta[domain] = domainAttrs;
325
326               if(approved === true){
327                 this.update(() => sendResponse(account), bytom);
328               }else{
329                 this.update(() => sendResponse(approved), bytom);
330               }
331             }
332           }));
333         }
334       }
335     })
336   }
337
338   static disauthenticate(sendResponse, payload){
339     Background.load(bytom => {
340       const domain = payload.domain;
341
342       var index = bytom.settings.domains.indexOf(domain);
343       if(index !== -1) {
344         payload.type = 'dis'
345         NotificationService.open(new Prompt(PromptTypes.REQUEST_AUTH, payload.domain, payload, approved => {
346           if (approved === false) sendResponse(Error.forbidden())
347           else if(approved.hasOwnProperty('isError')) sendResponse(approved);
348           else {
349             bytom.settings.domains.splice(index, 1);
350             delete bytom.settings.domainsMeta[domain];
351
352             if(approved === true){
353               this.update(() => sendResponse({status:'success'}), bytom);
354             }else{
355               this.update(() => sendResponse(approved), bytom);
356             }
357           }
358         }));
359       } else{
360         sendResponse(Error.disauth());
361       }
362     })
363   }
364
365
366 }
367
368 window.setLockTime = (time) => lockTime = time || Date.now();
369 window.getLockTime = () => lockTime;
370
371 new Background()