/ src / server / spec.js
spec.js
  1  import express from 'express'
  2  const router = express.Router()
  3  
  4  import state from './state.js'
  5  import utils from './utils.js'
  6  import validators from './validators.js'
  7  import calculations from '../calculations.js'
  8  import events from './events.js'
  9  //import connector from './connector.js'
 10  import lightning from './lightning.js'
 11  
 12  router.post('/events', (req, res, next) => {
 13      state.serverState.sessions.forEach(s => {
 14          if (s.token === req.headers.authorization){
 15              req.body.blame = s.ownerId
 16          }
 17      })
 18      next()
 19  })
 20  
 21  import fs from 'fs'
 22  import chalk from 'chalk'
 23  import crypto from 'crypto'
 24  import { config } from './configParser.js'
 25  const priv = fs.readFileSync(config.aodir + '/key')
 26  
 27  router.post('/events', (req, res, next)=>{
 28    let errRes = []
 29    switch (req.body.type){
 30        case "completed-toggled":
 31            if (
 32              validators.isTaskId(req.body.taskId, errRes)
 33            ) {
 34              events.completedToggled(
 35                req.body.taskId,
 36                req.body.blame,
 37                utils.buildResCallback(res)
 38              )
 39            } else {
 40              res.status(400).send(errRes);
 41            }
 42            break
 43        case "member-purged":
 44            let isActive = state.serverState.members.some(m => {
 45                if (m.memberId === req.body.memberId && (m.boost > 0 || m.active)){
 46                    return true
 47                }
 48            })
 49            if (
 50              validators.isMemberId(req.body.memberId, errRes) &&
 51              !isActive
 52            ) {
 53              events.memberPurged(
 54                req.body.memberId,
 55                req.body.blame,
 56                utils.buildResCallback(res)
 57              )
 58            } else {
 59              res.status(400).send(errRes);
 60            }
 61            break
 62        case "task-colored":
 63            if (
 64              validators.isTaskId(req.body.taskId, errRes) &&
 65              validators.isTaskId(req.body.inId, errRes) &&
 66              validators.isNotes(req.body.color, errRes)
 67            ) {
 68              events.taskColored(
 69                req.body.taskId,
 70                req.body.inId,
 71                req.body.color,
 72                req.body.blame,
 73                utils.buildResCallback(res)
 74              )
 75            } else {
 76              res.status(400).send(errRes);
 77            }
 78            break
 79        case "task-locked":
 80            state.serverState.members.some( m => {
 81                if (m.memberId === req.body.blame){
 82                    console.log(chalk.bold( crypto.privateDecrypt(priv, Buffer.from(req.body.name, 'hex') ).toString('latin1')))
 83                    console.log( chalk.bold.magenta('-', m.name))
 84                    events.taskCreated(
 85                      "__lock:" + req.body.name,
 86                      req.body.color,
 87                      req.body.deck,
 88                      req.body.inId,
 89                      req.body.blame,
 90                      utils.buildResCallback(res)
 91                    )
 92                }
 93            })
 94            break
 95        case "address-updated":
 96            if (validators.isTaskId(req.body.taskId, errRes)){
 97                lightning.newAddress()
 98                    .then(result => {
 99                        events.addressUpdated(
100                          req.body.taskId,
101                          result['bech32'],
102                          req.body.blame,
103                          utils.buildResCallback(res)
104                        )
105                    })
106                .catch(console.log)
107            }
108            break
109        case "task-seized":
110            if (
111              validators.isTaskId(req.body.taskId, errRes) &&
112              validators.isTaskId(req.body.inId, errRes)
113            ) {
114              events.taskSeized(
115                  req.body.taskId,
116                  req.body.inId,
117                  utils.buildResCallback(res)
118              );
119            } else {
120              res.status(400).send(errRes);
121            }
122            break
123        case "task-touched":
124            if (
125              validators.isTaskId(req.body.taskId, errRes) &&
126              validators.isNotes(req.body.stack, errRes)  &&
127              validators.yesSir(req.body.position, errRes) &&
128              validators.yesSir(req.body.value, errRes)
129            ) {
130              events.taskTouched(
131                req.body.taskId,
132                req.body.stack,
133                req.body.position,
134                req.body.blame,
135                utils.buildResCallback(res)
136              );
137            } else {
138              res.status(400).send(errRes);
139            }
140            break
141        case "task-valued":
142          if (
143            validators.isTaskId(req.body.taskId, errRes) &&
144            validators.isAmount(req.body.value, errRes)
145          ) {
146            req.body.value = req.body.value.toString()
147            events.taskValued(
148              req.body.taskId,
149              req.body.value,
150              req.body.blame,
151              utils.buildResCallback(res)
152            );
153            lightning
154                .createInvoice(req.body.value, "ao <3: " +  crypto.randomUUID(), '~ ao ~', 3600)
155                .then(result => {
156                    console.log("invoice result?>>>" , result)
157                    events.invoiceCreated(req.body.taskId, result.bolt11, result.payment_hash, req.body.blame)
158                })
159                .catch(err => {
160                    console.log(err)
161                });
162          } else {
163            res.status(400).send(errRes);
164          }
165          break
166        case "task-popped":
167            if (
168              validators.isTaskId(req.body.taskId, errRes) &&
169              validators.isTaskId(req.body.inId, errRes)
170            ) {
171              events.taskPopped(
172                req.body.taskId,
173                req.body.inId,
174                req.body.blame,
175                utils.buildResCallback(res)
176              );
177            } else {
178              res.status(400).send(errRes);
179            }
180            break
181        case "pile-prioritized":
182            if (
183                validators.isTaskId(req.body.inId, errRes) &&
184                req.body.tasks.every(tId => {
185                    console.log("validating tId") 
186                    validators.isTaskId(tId, errRes)
187                })
188            ) {
189                events.pilePrioritized(req.body.inId, req.body.tasks, req.body.blame, utils.buildResCallback(res));
190            } else {
191                res.status(400).send(errRes);
192            }
193            break
194        case "pile-sub-tasked":
195            if (
196                validators.isTaskId(req.body.inId, errRes) &&
197                req.body.tasks.every(tId => validators.isTaskId(tId, errRes))
198            ) {
199                events.pileSubTasked(req.body.inId, req.body.tasks, req.body.blame, utils.buildResCallback(res));
200            } else {
201                res.status(400).send(errRes);
202            }
203            break
204        case "pile-de-sub-tasked":
205            if (
206                validators.isTaskId(req.body.inId, errRes) &&
207                req.body.tasks.every(tId => validators.isTaskId(tId, errRes))
208            ) {
209                events.pileDeSubTasked(req.body.inId, req.body.tasks, req.body.blame, utils.buildResCallback(res));
210            } else {
211                res.status(400).send(errRes);
212            }
213            break
214        case 'highlighted':
215            if (
216                validators.isTaskId(req.body.taskId, errRes) &&
217                validators.isMemberId(req.body.memberId, errRes) &&
218                validators.isBool(req.body.valence, errRes)
219            ){
220                events.highlighted(req.body.taskId, req.body.memberId, req.body.valence, req.body.blame, utils.buildResCallback(res))
221            } else {
222                res.status(400).send(errRes)
223            }
224            break
225        case 'ao-disconnected':
226            if (validators.isAddress(req.body.address, errRes)){
227                events.aoDisconnected(
228                  req.body.address,
229                  utils.buildResCallback(res)
230                )
231            } else {
232                res.status(400).send(errRes)
233            }
234            break
235        case 'rent-set':
236            if (
237                validators.isAmount(req.body.amount, errRes)
238            ){
239                events.rentSet(
240                  req.body.amount,
241                  utils.buildResCallback(res)
242                )
243            } else {
244                res.status(400).send(errRes)
245            }
246            break
247        case 'cap-set':
248            if (
249                validators.isAmount(req.body.amount, errRes)
250            ){
251                events.capSet(
252                  req.body.amount,
253                  utils.buildResCallback(res)
254                )
255            } else {
256                res.status(400).send(errRes)
257            }
258            break
259        // Inter-AO functions are disabled until tor or o7s can be reintegrated.
260        //case 'ao-outbound-connected':
261        //    connector.postEvent(req.body.address, req.body.secret, {
262        //        type: 'ao-inbound-connected',
263        //        alias: state.serverState.cash.alias,
264        //        address: state.serverState.cash.address.trim(),
265        //        secret: req.body.secret, //
266        //    }, (err, subscriptionResponse) => {
267        //        if (err || !subscriptionResponse  || !subscriptionResponse.lastInsertRowid){
268        //            return res.status(200).send(['ao-connect failed'])
269        //        }
270        //        events.aoOutboundConnected(
271        //          req.body.address,
272        //          req.body.secret,
273        //          utils.buildResCallback(res)
274        //        )
275        //    })
276        //    break
277        //case 'ao-inbound-connected':
278        //    if (
279        //        validators.isNotes(req.body.address, errRes) &&
280        //        validators.isNotes(req.body.secret, errRes)
281        //    ){
282        //        events.aoInboundConnected(
283        //          req.body.address.trim(),
284        //          req.body.alias || 'ao', 
285        //          req.body.secret,
286        //          utils.buildResCallback(res)
287        //        )
288        //    } else {
289        //        res.status(400).send(errRes)
290        //    }
291        //    break
292        //case 'ao-relay':
293        //    let secret
294        //    state.serverState.ao.forEach(a => {
295        //        if (a.address == req.body.address){
296        //            secret = a.outboundSecret
297        //        }
298        //    })
299        //    if (secret){
300        //        connector.postEvent(req.body.address, secret, req.body.ev, (err, connectorRes) => {
301        //            if (err){
302        //                res.status(400).send(err)
303        //            } else {
304        //                res.status(201).send(connectorRes)
305        //            }
306        //        })
307        //    } else {
308        //        console.log("no connection for ", req.body.address)
309        //        next()
310        //    }
311        //    break
312        case 'invoice-created':
313            if (
314                validators.isTaskId(req.body.taskId, errRes) &&
315                validators.isAmount(req.body.amount, errRes)
316            ) {
317                lightning.createInvoice(req.body.amount, "<3" +  crypto.randomUUID(), '~', 3600)
318                    .then(result => {
319                        events.invoiceCreated(req.body.taskId, result.bolt11, result.payment_hash, req.body.blame, utils.buildResCallback(res))
320                    })
321                    .catch(err => {
322                        console.log({err})
323                        res.status(200).send("attempt failed")
324                    });
325            } else {
326              res.status(400).send(errRes)
327            }
328            break
329        case 'member-created':
330            if (
331                validators.isValidName(req.body.name, errRes) &&
332                validators.isNotes(req.body.fob, errRes) &&
333                validators.isNotes(req.body.secret)
334            ){
335              events.memberCreated(
336                req.body.name,
337                req.body.fob,
338                req.body.secret,
339                utils.buildResCallback(res)
340              )
341            } else {
342              res.status(400).send(errRes)
343            }
344            break
345        case 'member-activated':
346            if (
347              validators.isMemberId(req.body.memberId, errRes)
348            ){
349              events.memberActivated(
350                req.body.memberId,
351                utils.buildResCallback(res)
352              )
353            } else {
354              res.status(400).send(errRes)
355            }
356            break
357        case 'member-deactivated':
358            if (
359              validators.isMemberId(req.body.memberId, errRes)
360            ){
361              events.memberDeactivated(
362                req.body.memberId,
363                utils.buildResCallback(res)
364              )
365            } else {
366              res.status(400).send(errRes)
367            }
368            break
369        case 'member-field-updated':
370            if (
371                validators.isMemberId(req.body.memberId, errRes) &&
372                validators.isField(req.body.field, errRes) &&
373                validators.yesSir(req.body.newfield, errRes)
374            ){
375                if  (req.body.field === 'name' && !validators.isValidName(req.body.newfield, errRes)) {
376                    return res.status(400).send(errRes)
377                }
378                events.memberFieldUpdated(
379                    req.body.memberId,
380                    req.body.field,
381                    req.body.newfield,
382                    utils.buildResCallback(res)
383                )
384            } else {
385                res.status(400).send(errRes)
386            }
387            break
388        case 'resource-created':
389            console.log('trying',req.body.resourceId,req.body.name,req.body.charged,req.body.secret,req.body.trackStock)
390            if (
391              validators.isNewResourceId(req.body.resourceId, errRes) &&
392              validators.isNotes(req.body.name, errRes) &&
393              validators.isAmount(req.body.charged, errRes) &&
394              validators.isNotes(req.body.secret, errRes) &&
395              validators.isBool(req.body.trackStock, errRes)
396            ){
397              events.resourceCreated(
398                req.body.resourceId,
399                req.body.name,
400                req.body.charged,
401                req.body.secret,
402                req.body.trackStock,
403                utils.buildResCallback(res)
404              )
405            } else {
406              console.log(errRes)
407              res.status(400).send(errRes)
408            }
409            break
410        case 'resource-used':
411            let member = validators.isActiveMemberId(req.body.memberId, errRes)
412            let resource = validators.isResourceId(req.body.resourceId, errRes)
413            let memberTask = validators.isTaskId(member.memberId, errRes)
414            let canAccess = calculations.access(member.active, memberTask.boost, resource.charged)
415            if (
416                member &&
417                resource &&
418                validators.isAmount(req.body.charged, errRes) &&
419                validators.isNotes(req.body.notes, errRes) &&
420                canAccess
421            ){
422                events.resourceUsed(
423                  req.body.resourceId,
424                  req.body.memberId,
425                  req.body.charged,
426                  req.body.notes,
427                  utils.buildResCallback(res)
428                )
429            } else {
430                res.status(400).send(errRes)
431            }
432            break
433        case 'resource-stocked':
434            if (
435              validators.isResourceId(req.body.resourceId, errRes) &&
436              validators.isMemberId(req.body.memberId, errRes) &&
437              validators.isAmount(req.body.amount, errRes) &&
438              validators.isAmount(req.body.paid, errRes) &&
439              validators.yesSir(req.body.notes, errRes)
440            ){
441              events.resourceStocked(
442                  req.body.resourceId,
443                  req.body.memberId,
444                  req.body.amount,
445                  req.body.paid,
446                  req.body.notes,
447                  utils.buildResCallback(res)
448              )
449            } else {
450              res.status(400).send(errRes)
451            }
452            break
453        case 'resource-booked':
454            if (
455              validators.isTaskId(req.body.resourceId, errRes) &&
456              validators.isMemberId(req.body.blame, errRes) &&
457              validators.yesSir(req.body.startTs, errRes) &&
458              validators.yesSir(req.body.endTs, errRes) &&
459              validators.yesSir(req.body.charge, errRes) &&
460              validators.yesSir(req.body.notes, errRes)
461            ){
462              events.resourceBooked(
463                req.body.resourceId,
464                req.body.blame,
465                req.body.startTs,
466                req.body.endTs,
467                req.body.charge,
468                req.body.notes,
469                utils.buildResCallback(res)
470              )
471            } else {
472              res.status(400).send(errRes)
473            }
474            break
475        case 'session-killed':
476            if (
477              validators.isSession(req.body.session, errRes)
478            ){
479              events.sessionKilled(
480                req.body.session,
481                utils.buildResCallback(res)
482              )
483            } else {
484              res.status(400).send(errRes)
485            }
486            break
487        case 'task-created':
488            if (
489              validators.isNotes(req.body.name, errRes) &&
490              validators.isNotes(req.body.color, errRes) &&
491              validators.isNotes(req.body.deck, errRes) &&
492              validators.isTaskId(req.body.inId, errRes)
493            ){
494                events.taskCreated(
495                    req.body.name,
496                    req.body.color,
497                    req.body.deck,
498                    req.body.inId,
499                    req.body.blame,
500                    utils.buildResCallback(res)
501                )
502            } else {
503              res.status(400).send(errRes)
504            }
505            break
506        case 'task-guilded':
507            if (
508                validators.isTaskId(req.body.taskId, errRes) &&
509                validators.yesSir(req.body.guild, errRes)
510            ){
511                events.taskGuilded(
512                  req.body.taskId,
513                  req.body.guild,
514                  req.body.blame,
515                  utils.buildResCallback(res)
516                )
517            } else {
518                res.status(400).send(errRes)
519            }
520            break
521        case 'task-sub-tasked':
522            if (
523              validators.isTaskId(req.body.taskId, errRes) &&
524              validators.isTaskId(req.body.inId, errRes)
525            ){
526              events.taskSubTasked(
527                req.body.taskId,
528                req.body.inId,
529                req.body.blame,
530                utils.buildResCallback(res)
531              )
532  
533  
534            } else {
535              res.status(400).send(errRes)
536            }
537            break
538        case 'task-de-sub-tasked':
539            if (
540              validators.isTaskId(req.body.taskId, errRes) &&
541              validators.isTaskId(req.body.inId, errRes)
542            ){
543              events.taskDeSubTasked(
544                req.body.taskId,
545                req.body.inId,
546                req.body.blame,
547                utils.buildResCallback(res)
548              )
549            } else {
550              res.status(400).send(errRes)
551            }
552            break
553        case 'task-claimed':
554            if (
555              validators.isTaskId(req.body.taskId, errRes) &&
556              validators.isTaskId(req.body.inId, errRes)
557            ){
558              events.taskClaimed(
559                req.body.taskId,
560                req.body.blame,
561                req.body.inId,
562                utils.buildResCallback(res)
563              )
564            } else {
565                res.status(400).send(errRes)
566            }
567            break
568        case 'task-unclaimed':
569            if (
570              validators.isTaskId(req.body.taskId, errRes) &&
571              validators.isTaskId(req.body.inId, errRes)
572            ){
573              events.taskUnclaimed(
574                req.body.taskId,
575                req.body.blame,
576                req.body.inId,
577                utils.buildResCallback(res)
578              )
579            } else {
580                res.status(400).send(errRes)
581            }
582            break
583        case 'task-removed':
584            if (
585                validators.isMemberId(req.body.taskId, errRes)
586            ){
587                events.memberPurged(
588                  req.body.taskId,
589                  req.body.blame,
590                  utils.buildResCallback(res)
591                )
592            } else if (
593                validators.isResourceId(req.body.taskId, errRes)
594            ){
595                events.resourcePurged(
596                  req.body.taskId,
597                  req.body.blame,
598                  utils.buildResCallback(res)
599                )
600            } else if (
601                validators.isTaskId(req.body.taskId, errRes)
602            ){
603                events.taskRemoved(
604                  req.body.taskId,
605                  req.body.blame,
606                  utils.buildResCallback(res)
607                )
608            } else {
609                res.status(400).send(errRes)
610            }
611            break
612        case 'task-grabbed':
613            if (
614                validators.isTaskId(req.body.taskId, errRes) &&
615                req.body.taskId !== req.body.blame
616            ){
617                events.taskGrabbed(
618                  req.body.taskId,
619                  req.body.blame,
620                  utils.buildResCallback(res)
621                )
622            } else {
623              res.status(400).send(errRes)
624            }
625            break
626        case 'task-dropped':
627            if (
628                validators.isTaskId(req.body.taskId, errRes) && 
629                req.body.taskId !== req.body.blame
630            ){
631                events.taskDropped(
632                    req.body.taskId,
633                    req.body.blame,
634                    utils.buildResCallback(res)
635                )
636            } else {
637                res.status(400).send(errRes)
638            }
639            break
640        case 'task-swapped':
641            if (
642                validators.isTaskId(req.body.taskId, errRes) &&
643                validators.isTaskId(req.body.swapId1, errRes) &&
644                validators.isTaskId(req.body.swapId2, errRes)
645            ) {
646                events.taskSwapped(
647                  req.body.taskId,
648                  req.body.swapId1,
649                  req.body.swapId2,
650                  req.body.blame,
651                  utils.buildResCallback(res)
652                )
653            } else {
654              res.status(400).send(errRes)
655            }
656            break
657        case 'task-prioritized':
658            if (
659                validators.isTaskId(req.body.inId, errRes) &&
660                validators.isTaskId(req.body.fromId, errRes) &&
661                validators.isTaskId(req.body.taskId, errRes)
662            ){
663                events.taskPrioritized(
664                  req.body.taskId,
665                  req.body.inId,
666                  req.body.fromId,
667                  req.body.blame,
668                  utils.buildResCallback(res)
669                )
670            } else {
671                res.status(400).send(errRes)
672            }
673            break
674        case 'task-completed':
675            if (
676                validators.isTaskId(req.body.inId, errRes) &&
677                validators.isTaskId(req.body.taskId, errRes)
678            ){
679                events.taskCompleted(
680                  req.body.taskId,
681                  req.body.inId,
682                  req.body.blame,
683                  utils.buildResCallback(res)
684                )
685            } else {
686                res.status(400).send(errRes)
687            }
688            break
689        case 'tasks-received':
690            if (true) { // XXX
691                let safeTasks = req.body.tasks.map(t => { // hard question
692                    t.deck = []
693                    return t
694                })
695                events.tasksReceived(
696                  safeTasks,
697                  req.body.blame,
698                  utils.buildResCallback(res))
699            } else {
700              res.status(400).send(errRes)
701            }
702            break
703        default:
704            next()
705      }
706  })
707  
708  export default router