Compare commits

...

92 commits

Author SHA1 Message Date
kevkevin
ebcc2e0703
fix: disabling pingHubInterval since it is causing large queries (#813) 2024-07-16 08:59:30 -05:00
github-actions[bot]
f879688d62 [ci commit] Update proto files and types 2024-04-10 16:04:41 +00:00
github-actions[bot]
92a66aa3d4 [ci commit] Lint and format code 2024-04-10 16:04:11 +00:00
Evan Feenstra
332923b13b
Merge pull request #808 from stakwork/fix/edit-tribe
update: ensured empty string app_url are saved
2024-04-10 09:02:50 -07:00
Oluwatobi Bamidele
63d82c88c3 update: ensured empty string app_url are saved 2024-04-10 15:46:35 +01:00
github-actions[bot]
3843f44199 [ci commit] Update proto files and types 2024-04-01 20:30:22 +00:00
github-actions[bot]
d190bd85f2 [ci commit] Lint and format code 2024-04-01 20:29:53 +00:00
Evan Feenstra
78cd8a0548 fix interceptTribeMsgForHiddenCmds 2024-04-01 13:28:28 -07:00
github-actions[bot]
3330338f4a [ci commit] Update proto files and types 2024-03-28 16:50:45 +00:00
github-actions[bot]
6970098eb9 [ci commit] Automatic build 2024-03-28 16:50:26 +00:00
github-actions[bot]
3dc5029c37 [ci commit] Lint and format code 2024-03-28 16:50:15 +00:00
Evan Feenstra
c0962f5f27
Merge pull request #807 from stakwork/update/kick-bot
Update/kick bot
2024-03-28 09:48:50 -07:00
Oluwatobi Bamidele
48d023e96b update: ensured install and uninstall commands entered by the admin is not visible to users 2024-03-27 21:01:24 +01:00
Oluwatobi Bamidele
f54d2f5bbb update: hide install and uninstall response 2024-03-27 20:03:03 +01:00
Oluwatobi Bamidele
57f77c5884 update: hide all commands related to kick bot 2024-03-27 19:24:47 +01:00
Oluwatobi Bamidele
50272a7d7e update: ensured help command response are hidden 2024-03-27 19:05:45 +01:00
github-actions[bot]
7bf43c4a49 [ci commit] Update proto files and types 2024-03-22 14:50:31 +00:00
github-actions[bot]
9dfaff50ff [ci commit] Lint and format code 2024-03-22 14:50:02 +00:00
Evan Feenstra
e27d93257c
Merge pull request #806 from stakwork/update/second-brain-url
Update/second brain url
2024-03-22 07:48:45 -07:00
Oluwatobi Bamidele
36d4ebf010 update: update second_brain_url on tribe server 2024-03-21 22:14:25 +01:00
Oluwatobi Bamidele
d16c1de085 feat: added second_brain_url to create tribe on tribe server 2024-03-21 22:09:23 +01:00
github-actions[bot]
ca62559eca [ci commit] Update proto files and types 2024-03-19 20:07:29 +00:00
github-actions[bot]
ee4299692e [ci commit] Lint and format code 2024-03-19 20:07:00 +00:00
Evan Feenstra
30cef93979
Merge pull request #805 from stakwork/feat/second_brain_url
Feat/second brain url
2024-03-19 13:05:38 -07:00
Oluwatobi Bamidele
5b271982a0 update: added second brain url to update tribe 2024-03-19 19:09:31 +01:00
Oluwatobi Bamidele
5a7b191db1 feat: add second_brain_url when creating a tribe 2024-03-19 18:57:44 +01:00
Oluwatobi Bamidele
205a0fa455 feat: added second_brain_url column to chats table 2024-03-19 18:54:03 +01:00
github-actions[bot]
a3b3528a2c [ci commit] Update proto files and types 2024-02-08 00:07:55 +00:00
github-actions[bot]
a28d55e705 [ci commit] Lint and format code 2024-02-08 00:07:25 +00:00
Evan Feenstra
4e99a468ba
Merge pull request #802 from stakwork/update/only_pubkey
Update/only pubkey
2024-02-07 16:05:56 -08:00
Oluwatobi Bamidele
ca66dbe5e5 Merge branch 'master' into update/only_pubkey 2024-02-07 23:36:27 +01:00
Oluwatobi Bamidele
2a47d076b3 update: only_pubkey takes multiple pubkey by seperating commas 2024-02-07 23:34:51 +01:00
github-actions[bot]
c8818b82a6 [ci commit] Update proto files and types 2024-02-05 20:52:56 +00:00
github-actions[bot]
a9c6c0a654 [ci commit] Lint and format code 2024-02-05 20:52:26 +00:00
Evan Feenstra
226c851fcf
Merge pull request #801 from stakwork/update/receipt_pubkey
Update/receipt pubkey
2024-02-05 12:51:07 -08:00
Oluwatobi Bamidele
25c31b12a5 update: added recipient pubkey 2024-02-02 23:10:23 +01:00
Oluwatobi Bamidele
fbe3d5b294 update: added recipient pubkey to bot pay api 2024-02-02 22:04:34 +01:00
github-actions[bot]
70667d583d [ci commit] Update proto files and types 2024-01-30 20:55:02 +00:00
github-actions[bot]
32b3b27a82 [ci commit] Lint and format code 2024-01-30 20:54:31 +00:00
Evan Feenstra
fc11ae7e18
Merge pull request #800 from stakwork/fix/pay-by-bot
Fix/pay by bot
2024-01-30 12:53:08 -08:00
Oluwatobi Bamidele
36773e3a3c update: direct payment can also have content for bot payment 2024-01-30 21:16:53 +01:00
Oluwatobi Bamidele
49a3c53f11 update: if reply_uuid is not provided bot pay should be a direct payment 2024-01-30 21:04:50 +01:00
Oluwatobi Bamidele
aa13d7d374 fix: bot payment should actually send payment to recipient 2024-01-30 20:52:25 +01:00
github-actions[bot]
f0fef0912e [ci commit] Update proto files and types 2023-12-14 20:55:02 +00:00
github-actions[bot]
51c57673ae [ci commit] Lint and format code 2023-12-14 20:54:31 +00:00
Evan Feenstra
f63b20769a Merge branch 'master' of github.com:stakwork/sphinx-relay 2023-12-14 12:53:02 -08:00
Evan Feenstra
0d78b4a6a9 also rm hmac key and pushkit token from contact 2023-12-14 12:52:53 -08:00
github-actions[bot]
e1df351fc6 [ci commit] Update proto files and types 2023-12-14 20:49:50 +00:00
github-actions[bot]
2d7cfb58dd [ci commit] Lint and format code 2023-12-14 20:49:20 +00:00
Evan Feenstra
4af0fd7400 Merge branch 'master' of github.com:stakwork/sphinx-relay 2023-12-14 12:47:55 -08:00
Evan Feenstra
62c8c6b837 fix accounting tenant 2023-12-14 12:47:48 -08:00
github-actions[bot]
e941be6cd2 [ci commit] Update proto files and types 2023-12-14 20:39:09 +00:00
github-actions[bot]
feed373785 [ci commit] Lint and format code 2023-12-14 20:38:38 +00:00
Evan Feenstra
a238fcbb79 Merge branch 'master' of github.com:stakwork/sphinx-relay 2023-12-14 12:37:12 -08:00
Evan Feenstra
e523ef2da2 dont truncate 2023-12-14 12:37:03 -08:00
github-actions[bot]
a62896f390 [ci commit] Update proto files and types 2023-12-14 20:24:01 +00:00
github-actions[bot]
f97f6ba492 [ci commit] Lint and format code 2023-12-14 20:23:30 +00:00
Evan Feenstra
aacc9a6d0b Merge branch 'master' of github.com:stakwork/sphinx-relay 2023-12-14 12:21:51 -08:00
Evan Feenstra
180b668537 fix destroy non owner contacts 2023-12-14 12:21:43 -08:00
github-actions[bot]
d884d8059f [ci commit] Update proto files and types 2023-12-14 18:36:24 +00:00
github-actions[bot]
fddadf30e3 [ci commit] Lint and format code 2023-12-14 18:35:54 +00:00
Evan Feenstra
ec7d097bf3 Merge branch 'master' of github.com:stakwork/sphinx-relay 2023-12-14 10:34:27 -08:00
Evan Feenstra
8cfcb67d99 make sure tenant exists before deleting 2023-12-14 10:34:09 -08:00
github-actions[bot]
7dcd835334 [ci commit] Update proto files and types 2023-12-14 18:13:38 +00:00
github-actions[bot]
a5f85a9424 [ci commit] Lint and format code 2023-12-14 18:13:07 +00:00
Evan Feenstra
63795be857 test clear can be hit without the config 2023-12-14 10:11:39 -08:00
github-actions[bot]
ca64cfa5c3 [ci commit] Update proto files and types 2023-12-08 18:05:11 +00:00
github-actions[bot]
7c5a97a92a [ci commit] Lint and format code 2023-12-08 18:04:39 +00:00
Evan Feenstra
8e61585431 Merge branch 'master' of github.com:stakwork/sphinx-relay 2023-12-08 10:03:14 -08:00
Evan Feenstra
8da979190c move limiter to after logger 2023-12-08 10:03:02 -08:00
github-actions[bot]
031dd7d311 [ci commit] Update proto files and types 2023-12-08 17:49:37 +00:00
github-actions[bot]
14041b6a7b [ci commit] Lint and format code 2023-12-08 17:49:07 +00:00
Evan Feenstra
b14b3c81e2 move rate limiter to top level 2023-12-08 09:47:41 -08:00
github-actions[bot]
75400e5949 [ci commit] Update proto files and types 2023-12-01 18:20:20 +00:00
github-actions[bot]
4297586fa9 [ci commit] Lint and format code 2023-12-01 18:19:50 +00:00
Evan Feenstra
b8d26056f3 Merge branch 'master' of github.com:stakwork/sphinx-relay 2023-12-01 10:18:32 -08:00
Evan Feenstra
6d4050aa33 limit 10 per second 2023-12-01 10:18:13 -08:00
github-actions[bot]
8805e21b56 [ci commit] Update proto files and types 2023-12-01 17:31:14 +00:00
github-actions[bot]
cc8d704a4b [ci commit] Lint and format code 2023-12-01 17:30:43 +00:00
Evan Feenstra
72c4a749a8 rate limit all 2023-12-01 09:29:28 -08:00
github-actions[bot]
70be899cbe [ci commit] Update proto files and types 2023-10-30 22:12:50 +00:00
github-actions[bot]
775a5d541d [ci commit] Automatic build 2023-10-30 22:12:21 +00:00
github-actions[bot]
4df2a11d20 [ci commit] Lint and format code 2023-10-30 22:12:04 +00:00
uncleJim21
942ae31d49
add endpoint that can mark a given chat as read/unread (#776)
* add endpoint that can mark a given chat as read/unread

* attempt to resolve build issues

* try again

* test: added new test for marking messages as unread

* commit to force CI/CD to run again

* remove unnecessary notification

---------

Co-authored-by: kevkevin <oapallikunnel@gmail.com>
2023-10-30 17:06:02 -05:00
dependabot[bot]
7d1ab81a99
build(deps): bump browserify-sign from 4.2.1 to 4.2.2 (#783)
Bumps [browserify-sign](https://github.com/crypto-browserify/browserify-sign) from 4.2.1 to 4.2.2.
- [Changelog](https://github.com/browserify/browserify-sign/blob/main/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/browserify-sign/compare/v4.2.1...v4.2.2)

---
updated-dependencies:
- dependency-name: browserify-sign
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-30 17:04:02 -05:00
dependabot[bot]
bd114eecc9
build(deps): bump crypto-js from 4.1.1 to 4.2.0 (#782)
Bumps [crypto-js](https://github.com/brix/crypto-js) from 4.1.1 to 4.2.0.
- [Commits](https://github.com/brix/crypto-js/compare/4.1.1...4.2.0)

---
updated-dependencies:
- dependency-name: crypto-js
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-30 17:03:33 -05:00
github-actions[bot]
ebfd4947f8 [ci commit] Update proto files and types 2023-10-19 23:16:17 +00:00
github-actions[bot]
74bc26a570 [ci commit] Automatic build 2023-10-19 23:15:54 +00:00
github-actions[bot]
460901c7f0 [ci commit] Lint and format code 2023-10-19 23:15:39 +00:00
kevkevin
bf61d8b5ef
fix: updated workflow id for saving call recording (#780) 2023-10-19 18:14:10 -05:00
github-actions[bot]
ec56a8f44d [ci commit] Update proto files and types 2023-10-16 17:21:51 +00:00
github-actions[bot]
bd954e1eda [ci commit] Lint and format code 2023-10-16 17:21:10 +00:00
65 changed files with 917 additions and 217 deletions

View file

@ -52,6 +52,7 @@ jobs:
'externalHostedBot',
'spamGoneBot',
'mlBot',
'markMessageUnread',
]
node: [16]
steps:

17
app.ts
View file

@ -5,7 +5,7 @@ import * as cors from 'cors'
import * as https from 'https'
import * as http from 'http'
import logger, { logging, sphinxLogger } from './src/utils/logger'
import { pingHubInterval, checkInvitesHubInterval } from './src/hub'
import { checkInvitesHubInterval } from './src/hub'
import { genUsersInterval } from './src/utils/proxy'
import {
setupDatabase,
@ -25,6 +25,7 @@ import * as cert from './src/utils/cert'
import { loadConfig } from './src/utils/config'
import { Req } from './src/types'
import { leadershipBoardInterval } from './src/utils/leadershipboard'
import rateLimit from 'express-rate-limit'
// force UTC time
process.env.TZ = 'UTC'
@ -46,7 +47,7 @@ async function start() {
mainSetup()
// // IF NOT UNLOCK, go ahead and start this now
if (config.hub_api_url && !config.unlock) {
pingHubInterval(30000)
//pingHubInterval(30000)
genUsersInterval(60000)
}
}
@ -72,12 +73,19 @@ async function finishSetup() {
}
if (config.unlock) {
// IF UNLOCK, start this only after unlocked!
pingHubInterval(15000)
//pingHubInterval(15000)
}
leadershipBoardInterval(1800000)
setupDone()
}
const limiter = rateLimit({
windowMs: 1000, // 1 second
max: 10, // Limit each IP to 2 requests per `window` (here, per 1 second)
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
})
//
function setupApp() {
return new Promise(async (resolve) => {
@ -103,6 +111,9 @@ function setupApp() {
if (logging.Express) {
app.use(logger)
}
app.use(limiter)
app.use(
cors({
allowedHeaders: [

8
dist/app.js vendored
View file

@ -28,6 +28,7 @@ const grpc = require("./src/grpc/subscribe");
const cert = require("./src/utils/cert");
const config_1 = require("./src/utils/config");
const leadershipboard_1 = require("./src/utils/leadershipboard");
const express_rate_limit_1 = require("express-rate-limit");
// force UTC time
process.env.TZ = 'UTC';
const env = process.env.NODE_ENV || 'development';
@ -81,6 +82,12 @@ function finishSetup() {
(0, setup_1.setupDone)();
});
}
const limiter = (0, express_rate_limit_1.default)({
windowMs: 1000,
max: 10,
standardHeaders: true,
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
});
//
function setupApp() {
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
@ -103,6 +110,7 @@ function setupApp() {
if (logger_1.logging.Express) {
app.use(logger_1.default);
}
app.use(limiter);
app.use(cors({
allowedHeaders: [
'X-Requested-With',

2
dist/app.js.map vendored

File diff suppressed because one or more lines are too long

View file

@ -168,7 +168,8 @@ function init() {
},
{ name: 'Help', value: '/kick help' },
])
.setThumbnail(botSVG);
.setThumbnail(botSVG)
.setOnlyOwner(true);
message.channel.send({ embed });
return;
}

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.init = void 0;
exports.init = exports.adminsOnlyBot = void 0;
// import * as SphinxBot from '../../../sphinx-bot'
const Sphinx = require("sphinx-bot");
const botapi_1 = require("../controllers/botapi");
@ -79,6 +79,7 @@ const builtInBotNames = {
spam_gone: 'SpamGoneBot',
[`${ml_1.ML_PREFIX.substring(1)}`]: ml_1.ML_BOTNAME,
};
exports.adminsOnlyBot = ['kick'];
function init() {
const client = new Sphinx.Client();
client.login('_', botapi_1.finalAction);
@ -108,7 +109,8 @@ function init() {
if (existing) {
const embed = new Sphinx.MessageEmbed()
.setAuthor('MotherBot')
.setDescription(botName + ' already installed');
.setDescription(botName + ' already installed')
.setOnlyOwner(exports.adminsOnlyBot.includes(botName) || false);
return message.channel.send({ embed });
}
const msgTypes = builtInBotMsgTypes[botName] || [
@ -132,7 +134,8 @@ function init() {
const theName = builtInBotNames[botName] || 'Bot';
const embed = new Sphinx.MessageEmbed()
.setAuthor('MotherBot')
.setDescription(theName + ' has been installed!');
.setDescription(theName + ' has been installed!')
.setOnlyOwner(exports.adminsOnlyBot.includes(botName) || false);
message.channel.send({ embed });
}
else {
@ -144,7 +147,8 @@ function init() {
if (existing) {
const embed = new Sphinx.MessageEmbed()
.setAuthor('MotherBot')
.setDescription(botName + ' already installed');
.setDescription(botName + ' already installed')
.setOnlyOwner(exports.adminsOnlyBot.includes(botName) || false);
return message.channel.send({ embed });
}
// bot from tribes registry
@ -159,7 +163,8 @@ function init() {
else {
const embed = new Sphinx.MessageEmbed()
.setAuthor('MotherBot')
.setDescription('No bot with that name');
.setDescription('No bot with that name')
.setOnlyOwner(exports.adminsOnlyBot.includes(botName) || false);
message.channel.send({ embed });
}
}
@ -182,13 +187,15 @@ function init() {
yield existing2.destroy();
const embed = new Sphinx.MessageEmbed()
.setAuthor('MotherBot')
.setDescription(botName2 + ' has been removed');
.setDescription(botName2 + ' has been removed')
.setOnlyOwner(exports.adminsOnlyBot.includes(botName2) || false);
return message.channel.send({ embed });
}
else {
const embed = new Sphinx.MessageEmbed()
.setAuthor('MotherBot')
.setDescription('Cant find a bot by that name');
.setDescription('Cant find a bot by that name')
.setOnlyOwner(exports.adminsOnlyBot.includes(botName2) || false);
return message.channel.send({ embed });
}
case 'search':

File diff suppressed because one or more lines are too long

View file

@ -178,7 +178,7 @@ function sendToStakwork(apikey, callId, filePathAndName, webhook, ownerPubkey, f
},
body: JSON.stringify({
name: `${callId} file`,
workflow_id: 6173,
workflow_id: 12346,
workflow_params: {
set_var: {
attributes: {

File diff suppressed because one or more lines are too long

View file

@ -28,21 +28,30 @@ function broadcast(a) {
const { chat, owner } = ret;
const tenant = owner.id;
if (only_user || only_pubkey) {
if (only_user) {
chat.contactIds = `[${only_user}]`;
}
else {
try {
const user = (yield models_1.models.Contact.findOne({
where: { tenant, publicKey: only_pubkey },
}));
if (user)
chat.contactIds = `[${user.id}]`;
if (only_pubkey) {
const pubkeysArray = only_pubkey.split(',');
const userIds = [];
for (let i = 0; i < pubkeysArray.length; i++) {
const publicKey = pubkeysArray[i];
try {
const user = (yield models_1.models.Contact.findOne({
where: { tenant, publicKey },
}));
if (user)
userIds.push(user.id);
}
catch (error) {
logger_1.sphinxLogger.error(`=> ERROR GETTING USER WITH THIS PUBKEY ${publicKey} ${error}`, logger_1.logging.Bots);
}
}
catch (error) {
logger_1.sphinxLogger.error(`=> ONLY_PUBKEY ERROR ${error}`, logger_1.logging.Bots);
if (userIds.length === 0) {
logger_1.sphinxLogger.error(`=> USERS WITH PUBKEYS PROVIDED DO NOT EXIST`, logger_1.logging.Bots);
return;
}
chat.contactIds = JSON.stringify([...userIds]);
}
else {
chat.contactIds = `[${only_user}]`;
}
}
const encryptedForMeText = rsa.encrypt(owner.contactKey, content || '');

View file

@ -1 +1 @@
{"version":3,"file":"broadcast.js","sourceRoot":"","sources":["../../../../src/controllers/botapi/broadcast.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,oCAAmC;AACnC,yCAAwC;AACxC,yCAAyE;AACzE,wCAAuC;AACvC,8CAA6C;AAC7C,6CAA4C;AAC5C,+CAAuC;AACvC,+CAA0D;AAE1D,mCAAgD;AAEhD,SAA8B,SAAS,CAAC,CAAS;;QAC/C,MAAM,EACJ,MAAM,EACN,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,SAAS,EACT,OAAO,EACP,UAAU,EACV,SAAS,EACT,WAAW,GACZ,GAAG,CAAC,CAAA;QAEL,qBAAY,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;QACrC,MAAM,GAAG,GAAG,MAAM,IAAA,sBAAc,EAAC,CAAC,CAAC,CAAA;QACnC,IAAI,CAAC,GAAG;YAAE,OAAM;QAChB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,CAAA;QAC3B,MAAM,MAAM,GAAW,KAAK,CAAC,EAAE,CAAA;QAE/B,IAAI,SAAS,IAAI,WAAW,EAAE;YAC5B,IAAI,SAAS,EAAE;gBACb,IAAI,CAAC,UAAU,GAAG,IAAI,SAAS,GAAG,CAAA;aACnC;iBAAM;gBACL,IAAI;oBACF,MAAM,IAAI,GAAG,CAAC,MAAM,eAAM,CAAC,OAAO,CAAC,OAAO,CAAC;wBACzC,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,WAAY,EAAE;qBAC3C,CAAC,CAAkB,CAAA;oBACpB,IAAI,IAAI;wBAAE,IAAI,CAAC,UAAU,GAAG,IAAI,IAAI,CAAC,EAAE,GAAG,CAAA;iBAC3C;gBAAC,OAAO,KAAK,EAAE;oBACd,qBAAY,CAAC,KAAK,CAAC,wBAAwB,KAAK,EAAE,EAAE,gBAAO,CAAC,IAAI,CAAC,CAAA;oBACjE,OAAM;iBACP;aACF;SACF;QAED,MAAM,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,IAAI,EAAE,CAAC,CAAA;QACvE,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC,CAAA;QAC/D,MAAM,OAAO,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;QACvC,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAA;QACvB,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;QACvB,MAAM,KAAK,GAAG,QAAQ,IAAI,KAAK,CAAA;QAC/B,MAAM,YAAY,GAAG,CAAC,CAAC,CAAA;QAEvB,MAAM,GAAG,GAAsD;YAC7D,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,IAAI,EAAE,QAAQ,IAAI,KAAK,CAAC,QAAQ,EAAE;YAClC,IAAI,EAAE,mBAAS,CAAC,aAAa,CAAC,OAAO;YACrC,MAAM,EAAE,YAAY;YACpB,MAAM,EAAE,MAAM,IAAI,CAAC;YACnB,IAAI,EAAE,IAAI;YACV,cAAc,EAAE,kBAAkB;YAClC,oBAAoB,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAC7C,MAAM,EAAE,mBAAS,CAAC,QAAQ,CAAC,SAAS;YACpC,SAAS,EAAE,UAAU,IAAI,EAAE;YAC3B,SAAS,EAAE,IAAI;YACf,SAAS,EAAE,IAAI;YACf,WAAW,EAAE,KAAK;YAClB,MAAM;YACN,SAAS,EAAE,UAAU,IAAI,SAAS,IAAI,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;SACjE,CAAA;QACD,IAAI,SAAS;YAAE,GAAG,CAAC,QAAQ,GAAG,SAAS,CAAA;QACvC,IAAI,OAAO;YAAE,GAAG,CAAC,SAAS,GAAG,OAAO,CAAA;QACpC,MAAM,UAAU,GAAG,CAAC,MAAM,eAAM,CAAC,IAAI,CAAC,OAAO,CAAC;YAC5C,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE;SAC/B,CAAC,CAAe,CAAA;QAEjB,IAAI,UAAU;YAAE,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAClD,MAAM,OAAO,GAAY,CAAC,MAAM,eAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAY,CAAA;QACtE,MAAM,CAAC,QAAQ,CACb;YACE,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC;SACxD,EACD,MAAM,CACP,CAAA;QACD,qDAAqD;QACrD,iEAAiE;QACjE,IAAI,CAAC,UAAU,EAAE;YACf,MAAM,OAAO,CAAC,WAAW,CAAC;gBACxB,IAAI,EAAE,IAAuB;gBAC7B,MAAM,kCACD,KAAK,CAAC,UAAU,KACnB,KAAK,EACL,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,mBAAS,CAAC,UAAU,CAAC,MAAM,EACjC,QAAQ,EAAE,OAAO,IAAI,EAAE,GACxB;gBACD,OAAO,EAAE;oBACP,OAAO,EAAE,OAAO;oBAChB,EAAE,EAAE,OAAO,CAAC,EAAE;oBACd,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,CAAC;iBAChC;gBACD,IAAI,EAAE,mBAAS,CAAC,aAAa,CAAC,OAAO;gBACrC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBAClC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;oBACb,OAAO,qBAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;gBAC9B,CAAC;gBACD,WAAW,EAAE,IAAI;aAClB,CAAC,CAAA;SACH;IACH,CAAC;CAAA;AAvGD,4BAuGC"}
{"version":3,"file":"broadcast.js","sourceRoot":"","sources":["../../../../src/controllers/botapi/broadcast.ts"],"names":[],"mappings":"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"}

View file

@ -134,7 +134,7 @@ function processAction(req, res) {
return (0, res_1.failure)(res, 'failed to parse webhook body json');
}
}
const { action, bot_id, bot_secret, pubkey, amount, content, chat_uuid, msg_uuid, reply_uuid, recipient_id, parent_id, only_pubkey, only_owner, } = body;
const { action, bot_id, bot_secret, pubkey, amount, content, chat_uuid, msg_uuid, reply_uuid, recipient_id, parent_id, only_pubkey, only_owner, recipient_pubkey, } = body;
if (!bot_id)
return (0, res_1.failure)(res, 'no bot_id');
const bot = (yield models_1.models.Bot.findOne({ where: { id: bot_id } }));
@ -169,6 +169,7 @@ function processAction(req, res) {
recipient_id: recipient_id ? parseInt(recipient_id) : 0,
only_pubkey: only_pubkey || '',
only_owner: only_owner || false,
recipient_pubkey: recipient_pubkey || '',
};
try {
const r = yield finalAction(a);

File diff suppressed because one or more lines are too long

View file

@ -17,13 +17,14 @@ const socket = require("../../utils/socket");
const constants_1 = require("../../constants");
const logger_1 = require("../../utils/logger");
const errMsgString_1 = require("../../utils/errMsgString");
const rsa = require("../../crypto/rsa");
const index_1 = require("./index");
function pay(a) {
return __awaiter(this, void 0, void 0, function* () {
const { amount, bot_name, msg_uuid, reply_uuid, recipient_id, parent_id } = a;
const { amount, bot_name, msg_uuid, reply_uuid, recipient_id, parent_id, content, recipient_pubkey, } = a;
logger_1.sphinxLogger.info(`=> BOT PAY ${JSON.stringify(a, null, 2)}`);
if (!a.recipient_id)
return logger_1.sphinxLogger.error(`no recipient_id`);
if (!recipient_id && !recipient_pubkey)
return logger_1.sphinxLogger.error(`no recipient detail`);
const ret = yield (0, index_1.validateAction)(a);
if (!ret)
return;
@ -31,27 +32,44 @@ function pay(a) {
const tenant = owner.id;
const alias = bot_name || owner.alias;
const botContactId = -1;
const encryptedForMeText = rsa.encrypt(owner.contactKey, content || '');
const encryptedText = rsa.encrypt(chat.groupKey, content || '');
const textMap = { chat: encryptedText };
let recipient_detail;
if (recipient_pubkey) {
try {
const user = (yield models_1.models.Contact.findOne({
where: { tenant, publicKey: recipient_pubkey },
}));
if (!user) {
logger_1.sphinxLogger.error(`=> RECIPIENT PUBKEY DOES NOT EXIST IN ADMIN RECORD`, logger_1.logging.Bots);
return;
}
recipient_detail = user.id;
}
catch (error) {
logger_1.sphinxLogger.error(`=> RECIPIENT PUBKEY ERROR ${error}`, logger_1.logging.Bots);
return;
}
}
else {
recipient_detail = recipient_id;
}
const date = new Date();
date.setMilliseconds(0);
const msg = {
chatId: chat.id,
uuid: msg_uuid || short.generate(),
type: constants_1.default.message_types.boost,
sender: botContactId,
amount: amount || 0,
date: date,
status: constants_1.default.statuses.confirmed,
replyUuid: reply_uuid || '',
createdAt: date,
updatedAt: date,
senderAlias: alias,
tenant,
};
const msg = Object.assign({ chatId: chat.id, uuid: msg_uuid || short.generate(), type: reply_uuid
? constants_1.default.message_types.boost
: constants_1.default.message_types.direct_payment, sender: botContactId, amount: amount || 0, date: date, status: constants_1.default.statuses.confirmed, replyUuid: reply_uuid || '', createdAt: date, updatedAt: date, senderAlias: alias, tenant }, (reply_uuid
? {}
: {
messageContent: encryptedForMeText,
remoteMessageContent: JSON.stringify(textMap),
}));
if (parent_id)
msg.parentId = parent_id;
const message = (yield models_1.models.Message.create(msg));
socket.sendJson({
type: 'boost',
type: reply_uuid ? 'boost' : 'direct_payment',
response: jsonUtils.messageToJson(message, chat, owner),
}, tenant);
yield network.sendMessage({
@ -65,7 +83,10 @@ function pay(a) {
replyUuid: message.replyUuid,
parentId: message.parentId || 0,
},
type: constants_1.default.message_types.boost,
amount: amount || 0,
type: reply_uuid
? constants_1.default.message_types.boost
: constants_1.default.message_types.direct_payment,
success: () => ({ success: true }),
failure: (e) => __awaiter(this, void 0, void 0, function* () {
const errorMsg = (0, errMsgString_1.errMsgString)(e);
@ -76,7 +97,7 @@ function pay(a) {
return logger_1.sphinxLogger.error(e);
}),
isForwarded: true,
realSatsContactId: recipient_id,
realSatsContactId: recipient_detail,
});
});
}

View file

@ -1 +1 @@
{"version":3,"file":"pay.js","sourceRoot":"","sources":["../../../../src/controllers/botapi/pay.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"pay.js","sourceRoot":"","sources":["../../../../src/controllers/botapi/pay.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,oCAAmC;AACnC,yCAAwC;AACxC,yCAA6D;AAC7D,8CAA6C;AAC7C,6CAA4C;AAC5C,+CAAuC;AACvC,+CAA0D;AAC1D,2DAAuD;AACvD,wCAAuC;AACvC,mCAAgD;AAEhD,SAA8B,GAAG,CAAC,CAAS;;QACzC,MAAM,EACJ,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,SAAS,EACT,OAAO,EACP,gBAAgB,GACjB,GAAG,CAAC,CAAA;QAEL,qBAAY,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;QAC7D,IAAI,CAAC,YAAY,IAAI,CAAC,gBAAgB;YACpC,OAAO,qBAAY,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAA;QAClD,MAAM,GAAG,GAAG,MAAM,IAAA,sBAAc,EAAC,CAAC,CAAC,CAAA;QACnC,IAAI,CAAC,GAAG;YAAE,OAAM;QAChB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,CAAA;QAC3B,MAAM,MAAM,GAAW,KAAK,CAAC,EAAE,CAAA;QAC/B,MAAM,KAAK,GAAG,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAA;QACrC,MAAM,YAAY,GAAG,CAAC,CAAC,CAAA;QACvB,MAAM,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,IAAI,EAAE,CAAC,CAAA;QACvE,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC,CAAA;QAC/D,MAAM,OAAO,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;QACvC,IAAI,gBAAgB,CAAA;QAEpB,IAAI,gBAAgB,EAAE;YACpB,IAAI;gBACF,MAAM,IAAI,GAAG,CAAC,MAAM,eAAM,CAAC,OAAO,CAAC,OAAO,CAAC;oBACzC,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE;iBAC/C,CAAC,CAAkB,CAAA;gBACpB,IAAI,CAAC,IAAI,EAAE;oBACT,qBAAY,CAAC,KAAK,CAChB,oDAAoD,EACpD,gBAAO,CAAC,IAAI,CACb,CAAA;oBACD,OAAM;iBACP;gBACD,gBAAgB,GAAG,IAAI,CAAC,EAAE,CAAA;aAC3B;YAAC,OAAO,KAAK,EAAE;gBACd,qBAAY,CAAC,KAAK,CAAC,6BAA6B,KAAK,EAAE,EAAE,gBAAO,CAAC,IAAI,CAAC,CAAA;gBACtE,OAAM;aACP;SACF;aAAM;YACL,gBAAgB,GAAG,YAAY,CAAA;SAChC;QAED,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAA;QACvB,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;QACvB,MAAM,GAAG,mBACP,MAAM,EAAE,IAAI,CAAC,EAAE,EACf,IAAI,EAAE,QAAQ,IAAI,KAAK,CAAC,QAAQ,EAAE,EAClC,IAAI,EAAE,UAAU;gBACd,CAAC,CAAC,mBAAS,CAAC,aAAa,CAAC,KAAK;gBAC/B,CAAC,CAAC,mBAAS,CAAC,aAAa,CAAC,cAAc,EAC1C,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,IAAI,CAAC,EACnB,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,mBAAS,CAAC,QAAQ,CAAC,SAAS,EACpC,SAAS,EAAE,UAAU,IAAI,EAAE,EAC3B,SAAS,EAAE,IAAI,EACf,SAAS,EAAE,IAAI,EACf,WAAW,EAAE,KAAK,EAClB,MAAM,IACH,CAAC,UAAU;YACZ,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC;gBACE,cAAc,EAAE,kBAAkB;gBAClC,oBAAoB,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;aAC9C,CAAC,CACP,CAAA;QACD,IAAI,SAAS;YAAE,GAAG,CAAC,QAAQ,GAAG,SAAS,CAAA;QACvC,MAAM,OAAO,GAAY,CAAC,MAAM,eAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAY,CAAA;QACtE,MAAM,CAAC,QAAQ,CACb;YACE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB;YAC7C,QAAQ,EAAE,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC;SACxD,EACD,MAAM,CACP,CAAA;QAED,MAAM,OAAO,CAAC,WAAW,CAAC;YACxB,IAAI,EAAE,IAAW;YACjB,MAAM,kCACD,KAAK,CAAC,UAAU,KACnB,KAAK,EACL,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,mBAAS,CAAC,UAAU,CAAC,KAAK,GACjC;YACD,OAAO,EAAE;gBACP,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,EAAE,EAAE,OAAO,CAAC,EAAE;gBACd,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,CAAC;aAChC;YACD,MAAM,EAAE,MAAM,IAAI,CAAC;YACnB,IAAI,EAAE,UAAU;gBACd,CAAC,CAAC,mBAAS,CAAC,aAAa,CAAC,KAAK;gBAC/B,CAAC,CAAC,mBAAS,CAAC,aAAa,CAAC,cAAc;YAC1C,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAClC,OAAO,EAAE,CAAO,CAAC,EAAE,EAAE;gBACnB,MAAM,QAAQ,GAAG,IAAA,2BAAY,EAAC,CAAC,CAAC,CAAA;gBAChC,MAAM,OAAO,CAAC,MAAM,CAAC;oBACnB,YAAY,EAAE,QAAQ;oBACtB,MAAM,EAAE,mBAAS,CAAC,QAAQ,CAAC,MAAM;iBAClC,CAAC,CAAA;gBACF,OAAO,qBAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YAC9B,CAAC,CAAA;YACD,WAAW,EAAE,IAAI;YACjB,iBAAiB,EAAE,gBAAgB;SACpC,CAAC,CAAA;IACJ,CAAC;CAAA;AAjHD,sBAiHC"}

View file

@ -371,7 +371,7 @@ function editTribe(req, res) {
if (!req.owner)
return (0, res_1.failure)(res, 'no owner');
const tenant = req.owner.id;
const { name, price_per_message, price_to_join, escrow_amount, escrow_millis, img, description, tags, unlisted, app_url, feed_url, feed_type, pin, call_recording, meme_server_location, jitsi_server, stakwork_api_key, stakwork_webhook, } = req.body;
const { name, price_per_message, price_to_join, escrow_amount, escrow_millis, img, description, tags, unlisted, app_url, feed_url, feed_type, pin, call_recording, meme_server_location, jitsi_server, stakwork_api_key, stakwork_webhook, second_brain_url, } = req.body;
const { id } = req.params;
if (!id)
return (0, res_1.failure)(res, 'group id is required');
@ -426,6 +426,7 @@ function editTribe(req, res) {
owner_pubkey: owner.publicKey,
pin: pin || '',
profile_filters: profile_filters || '',
second_brain_url,
});
}
catch (e) {
@ -448,9 +449,9 @@ function editTribe(req, res) {
obj.escrowMillis = escrow_millis;
if (unlisted || unlisted === false)
obj.unlisted = unlisted;
if (app_url)
if (app_url || app_url === '')
obj.appUrl = app_url;
if (feed_url)
if (feed_url || feed_url === '')
obj.feedUrl = feed_url;
if (feed_type)
obj.feedType = feed_type;
@ -468,6 +469,8 @@ function editTribe(req, res) {
obj.stakworkApiKey = stakwork_api_key;
if (stakwork_webhook)
obj.stakworkWebhook = stakwork_webhook;
if (second_brain_url || second_brain_url === '')
obj.secondBrainUrl = second_brain_url;
if (Object.keys(obj).length > 0) {
yield chat.update(obj);
}
@ -843,7 +846,7 @@ exports.replayChatHistory = replayChatHistory;
* @param {Object} [profile_filters] - The profile filters for the chat.
* @returns {Promise<Object>} - An object containing the tribe chat parameters.
*/
function createTribeChatParams(owner, contactIds, name, img, price_per_message, price_to_join, escrow_amount, escrow_millis, unlisted, is_private, app_url, feed_url, feed_type, tenant, pin, profile_filters, call_recording, meme_server_location, jitsi_server, stakwork_api_key, stakwork_webhook) {
function createTribeChatParams(owner, contactIds, name, img, price_per_message, price_to_join, escrow_amount, escrow_millis, unlisted, is_private, app_url, feed_url, feed_type, tenant, pin, profile_filters, call_recording, meme_server_location, jitsi_server, stakwork_api_key, stakwork_webhook, second_brain_url) {
return __awaiter(this, void 0, void 0, function* () {
const date = new Date();
date.setMilliseconds(0);
@ -885,6 +888,7 @@ function createTribeChatParams(owner, contactIds, name, img, price_per_message,
jitsiServer: jitsi_server || '',
stakworkApiKey: stakwork_api_key || '',
stakworkWebhook: stakwork_webhook || '',
secondBrainUrl: second_brain_url || '',
};
});
}

File diff suppressed because one or more lines are too long

View file

@ -261,7 +261,7 @@ function createGroupChat(req, res) {
if (!req.owner)
return (0, res_1.failure)(res, 'no owner');
const tenant = req.owner.id;
const { name, is_tribe, price_per_message, price_to_join, escrow_amount, escrow_millis, img, description, tags, unlisted, app_url, feed_url, feed_type, pin, call_recording, meme_server_location, jitsi_server, stakwork_api_key, stakwork_webhook, } = req.body;
const { name, is_tribe, price_per_message, price_to_join, escrow_amount, escrow_millis, img, description, tags, unlisted, app_url, feed_url, feed_type, pin, call_recording, meme_server_location, jitsi_server, stakwork_api_key, stakwork_webhook, second_brain_url, } = req.body;
let { profile_filters } = req.body;
if (profile_filters) {
if (!Array.isArray(profile_filters)) {
@ -300,7 +300,7 @@ function createGroupChat(req, res) {
let chatParams;
let okToCreate = true;
if (is_tribe) {
chatParams = (yield (0, chatTribes_1.createTribeChatParams)(owner, contact_ids, name, img, price_per_message, price_to_join, escrow_amount, escrow_millis, unlisted, req.body.private, app_url, feed_url, feed_type, tenant, pin, profile_filters || '', call_recording, meme_server_location, jitsi_server, stakwork_api_key, stakwork_webhook));
chatParams = (yield (0, chatTribes_1.createTribeChatParams)(owner, contact_ids, name, img, price_per_message, price_to_join, escrow_amount, escrow_millis, unlisted, req.body.private, app_url, feed_url, feed_type, tenant, pin, profile_filters || '', call_recording, meme_server_location, jitsi_server, stakwork_api_key, stakwork_webhook, second_brain_url));
if (chatParams.uuid) {
// publish to tribe server
try {
@ -326,6 +326,7 @@ function createGroupChat(req, res) {
owner_route_hint: owner.routeHint || '',
pin: pin || '',
profile_filters: profile_filters || '',
second_brain_url: second_brain_url || '',
});
}
catch (e) {

File diff suppressed because one or more lines are too long

View file

@ -243,26 +243,21 @@ function clearForTesting(req, res) {
if (!req.owner)
return (0, res_1.failure)(res, 'no owner');
const tenant = req.owner.id;
if (!config.allow_test_clearing) {
return (0, res_1.failure)(res, 'nope');
}
if (config.allow_test_clearing !== 'true') {
return (0, res_1.failure)(res, 'nope');
}
if (!tenant)
return (0, res_1.failure)(res, 'no tenant');
try {
yield models_1.models.Chat.destroy({ truncate: true, where: { tenant } });
yield models_1.models.Subscription.destroy({ truncate: true, where: { tenant } });
yield models_1.models.Accounting.destroy({ truncate: true, where: { tenant } });
yield models_1.models.Bot.destroy({ truncate: true, where: { tenant } });
yield models_1.models.BotMember.destroy({ truncate: true, where: { tenant } });
yield models_1.models.ChatBot.destroy({ truncate: true, where: { tenant } });
yield models_1.models.Invite.destroy({ truncate: true, where: { tenant } });
yield models_1.models.MediaKey.destroy({ truncate: true, where: { tenant } });
yield models_1.models.Message.destroy({ truncate: true, where: { tenant } });
yield models_1.models.Timer.destroy({ truncate: true, where: { tenant } });
yield models_1.models.Chat.destroy({ where: { tenant } });
yield models_1.models.Subscription.destroy({ where: { tenant } });
yield models_1.models.Bot.destroy({ where: { tenant } });
yield models_1.models.BotMember.destroy({ where: { tenant } });
yield models_1.models.ChatBot.destroy({ where: { tenant } });
yield models_1.models.Invite.destroy({ where: { tenant } });
yield models_1.models.MediaKey.destroy({ where: { tenant } });
yield models_1.models.Message.destroy({ where: { tenant } });
yield models_1.models.Timer.destroy({ where: { tenant } });
yield models_1.models.Contact.destroy({
where: {
isOwner: { [sequelize_1.Op.ne]: 1 },
isOwner: { [sequelize_1.Op.or]: [false, null] },
tenant,
},
});
@ -275,6 +270,8 @@ function clearForTesting(req, res) {
contactKey: '',
alias: '',
deviceId: '',
hmacKey: '',
pushKitToken: '',
});
(0, res_1.success)(res, { clean: true });
}

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ACTIONS = exports.set = void 0;
const express_rate_limit_1 = require("express-rate-limit");
const models_1 = require("../models");
const auth_1 = require("../auth");
const gitinfo = require("../utils/gitinfo");
@ -42,12 +41,6 @@ const lsats = require("./lsats");
const action = require("./actionHistory");
const feeds = require("./getFeeds");
const contentFeedStatus = require("./contentFeedStatus");
const limiter = (0, express_rate_limit_1.default)({
windowMs: 1000,
max: 2,
standardHeaders: true,
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
});
function set(app) {
return __awaiter(this, void 0, void 0, function* () {
builtInBots.init();
@ -89,8 +82,6 @@ function set(app) {
app.delete('/contacts/:id', contacts.deleteContact);
app.get('/latest_contacts', contacts.getLatestContacts);
app.post('/generate_external', contacts.generateOwnerWithExternalSigner);
app.post('/hmac_key', contacts.registerHmacKey);
app.get('/hmac_key', contacts.getHmacKey);
app.get('/contact/:contact_id', contacts.getContactById);
app.post('/profile', personal.createPeopleProfile);
app.delete('/profile', personal.deletePersonProfile);
@ -108,11 +99,11 @@ function set(app) {
app.get('/badge_per_tribe/:chat_id', personal.getBadgePerTribe);
app.post('/remove_badge', personal.removeBadgeFromTribe);
app.put('/reissue_badge', personal.reissueBadge);
app.get('/msgs', messages.getMsgs);
app.get('/allmessages', messages.getAllMessages);
app.get('/messages', messages.getMessages);
app.delete('/message/:id', messages.deleteMessage);
app.post('/messages/:chat_id/read', messages.readMessages);
app.post('/messages/:chat_id/toggleChatReadUnread', messages.toggleChatReadUnread);
app.post('/messages/clear', messages.clearMessages);
app.delete('/messages', messages.disappearingMessages);
app.get('/message/:uuid', messages.getMessageByUuid);
@ -202,8 +193,9 @@ function set(app) {
app.delete('/default_tribe/:id', auth_1.proxyAdminMiddleware, admin.removeDefaultJoinTribe);
app.get('/tribes', auth_1.proxyAdminMiddleware, admin.listTribes);
app.get('/admin_balance', auth_1.proxyAdminMiddleware, admin.adminBalance);
// rate limit these routes:
app.use(limiter);
app.get('/msgs', messages.getMsgs);
app.post('/hmac_key', contacts.registerHmacKey);
app.get('/hmac_key', contacts.getHmacKey);
app.post('/messages', messages.sendMessage);
app.post('/contacts/:id/keys', contacts.exchangeKeys);
app.post('/contacts', contacts.createContact);

File diff suppressed because one or more lines are too long

View file

@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.initializeDeleteMessageCronJobs = exports.receiveVoip = exports.disappearingMessages = exports.clearMessages = exports.readMessages = exports.receiveDeleteMessage = exports.receiveRepayment = exports.receiveBoost = exports.receiveMessage = exports.sendMessage = exports.deleteMessage = exports.getMsgs = exports.getAllMessages = exports.getMessages = exports.getMessageByUuid = void 0;
exports.initializeDeleteMessageCronJobs = exports.receiveVoip = exports.disappearingMessages = exports.clearMessages = exports.readMessages = exports.toggleChatReadUnread = exports.receiveDeleteMessage = exports.receiveRepayment = exports.receiveBoost = exports.receiveMessage = exports.sendMessage = exports.deleteMessage = exports.getMsgs = exports.getAllMessages = exports.getMessages = exports.getMessageByUuid = void 0;
const sequelize_1 = require("sequelize");
const underscore_1 = require("underscore");
const short = require("short-uuid");
@ -646,6 +646,69 @@ const receiveDeleteMessage = (payload) => __awaiter(void 0, void 0, void 0, func
});
exports.receiveDeleteMessage = receiveDeleteMessage;
/**
Either makes all messages of a chat read or it marks the last message of the given chat as unread.
@param {Req} req - The request object containing the chat ID.
@param {Res} res - The response object used to send the updated chat information.
@returns {Promise<void>} - An empty promise.
*/
const toggleChatReadUnread = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!req.owner)
return (0, res_1.failure)(res, 'no owner');
//
try {
const requestBody = JSON.parse(req.rawBody);
//We want to mark the chat as read
if (requestBody.shouldMarkAsUnread === false) {
// Call the readMessages function with the same req and res objects
const result = yield (0, exports.readMessages)(req, res);
return result; // Exit the function after calling readMessages
}
//we want to mark the last message + chat as unread
const chat_id = req.params.chat_id;
const owner = req.owner;
const tenant = owner.id;
// Find the latest message that is not from the user and has been read
const latestMessage = yield models_1.models.Message.findOne({
where: {
sender: {
[sequelize_1.Op.ne]: owner.id,
},
chatId: chat_id,
[sequelize_1.Op.or]: [{ seen: true }, { seen: null }],
tenant,
},
order: [['date', 'DESC']],
});
// Update just the latest message found in the database to mark it as unseen
if (latestMessage) {
yield latestMessage.update({ seen: false });
}
//mark the chat as unseen
const chat = (yield models_1.models.Chat.findOne({
where: { id: chat_id, tenant },
}));
if (chat) {
(0, hub_1.resetNotifyTribeCount)(parseInt(chat_id));
yield chat.update({ seen: false });
(0, res_1.success)(res, {});
socket.sendJson({
type: 'chat_unseen',
response: jsonUtils.chatToJson(chat),
}, tenant);
}
else {
(0, res_1.failure)(res, 'no chat');
}
}
catch (error) {
return (0, res_1.failureWithResponse)(res, 'Invalid JSON body', {
error: error.message,
});
}
});
exports.toggleChatReadUnread = toggleChatReadUnread;
/**
Updates the messages in the specified chat to mark them as seen by the owner and sends a notification to the other chat members.
@param {Req} req - The request object containing the chat ID.
@ -697,7 +760,7 @@ const clearMessages = (req, res) => __awaiter(void 0, void 0, void 0, function*
if (!req.owner)
return (0, res_1.failure)(res, 'no owner');
const tenant = req.owner.id;
yield models_1.models.Message.destroy({ where: { tenant }, truncate: true });
yield models_1.models.Message.destroy({ where: { tenant } });
(0, res_1.success)(res, {});
});
exports.clearMessages = clearMessages;

File diff suppressed because one or more lines are too long

View file

@ -198,6 +198,10 @@ __decorate([
sequelize_typescript_1.Column,
__metadata("design:type", String)
], Chat.prototype, "preview", void 0);
__decorate([
sequelize_typescript_1.Column,
__metadata("design:type", String)
], Chat.prototype, "secondBrainUrl", void 0);
Chat = __decorate([
(0, sequelize_typescript_1.Table)({ tableName: 'sphinx_chats', underscored: true })
], Chat);

View file

@ -1 +1 @@
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../../src/models/sql/chat.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../../src/models/sql/chat.ts"],"names":[],"mappings":"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"}

View file

@ -21,7 +21,7 @@ const logger_1 = require("../utils/logger");
const config_1 = require("../utils/config");
const errMsgString_1 = require("../utils/errMsgString");
const proxy_1 = require("../utils/proxy");
const ml_1 = require("../builtin/ml");
const mother_1 = require("../builtin/mother");
const intercept = require("./intercept");
const receive_1 = require("./receive");
const config = (0, config_1.loadConfig)();
@ -423,27 +423,47 @@ function compareAliases(alias1, alias2) {
});
return match;
}
function updateMessageToIsOnlyOwner(uuid, tenant) {
return __awaiter(this, void 0, void 0, function* () {
yield models_1.models.Message.update({
onlyOwner: true,
}, { where: { uuid, tenant } });
});
}
function interceptTribeMsgForHiddenCmds(msg, tenant) {
return __awaiter(this, void 0, void 0, function* () {
const hideAllCommandsBot = ['/kick', '/ml'];
try {
const content = msg.message.content;
const splitedContent = (content && content.split(' ')) || [];
if (splitedContent.length < 1)
return false;
// must be a "/" bot command
if (!splitedContent[0].startsWith('/')) {
return false;
}
if (splitedContent[0] === '/bot') {
if (mother_1.adminsOnlyBot.includes(splitedContent[2])) {
yield updateMessageToIsOnlyOwner(msg.message.uuid, tenant);
return true;
}
return false;
}
const newChat = (yield models_1.models.Chat.findOne({
where: { uuid: msg.chat.uuid },
}));
const bots = (yield models_1.models.ChatBot.findAll({
where: { tenant, chatId: newChat.id },
}));
const content = msg.message.content;
const splitedContent = (content && content.split(' ')) || [];
for (let i = 0; i < bots.length; i++) {
const bot = bots[i];
const isHidden = bot.botPrefix === splitedContent[0] &&
bot.hiddenCommands &&
JSON.parse(bot.hiddenCommands).includes(splitedContent[1]);
const isPersonal = bot.botPrefix === ml_1.ML_PREFIX;
if (isHidden || isPersonal) {
yield models_1.models.Message.update({
onlyOwner: true,
}, { where: { uuid: msg.message.uuid, tenant } });
const isDefaultHide = bot.botPrefix === splitedContent[0] &&
hideAllCommandsBot.includes(bot.botPrefix);
if (isHidden || isDefaultHide) {
yield updateMessageToIsOnlyOwner(msg.message.uuid, tenant);
return true;
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,97 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.unreadMessages = void 0;
const ava_1 = require("ava");
const helpers_1 = require("../utils/helpers");
const del_1 = require("../utils/del");
const save_1 = require("../utils/save");
const msg_1 = require("../utils/msg");
const nodes_1 = require("../nodes");
/*
npx ava src/tests/controllers/deleteMessages.test.ts --verbose --serial --timeout=2m
*/
(0, ava_1.default)('test message mark unread: create tribe, join tribe, send messages, read messages, mark unread messages, check number of messages, leave tribe, delete tribe', (t) => __awaiter(void 0, void 0, void 0, function* () {
yield unreadMessages(t, 0, 1, 2);
}));
function unreadMessages(t, index1, index2, index3) {
return __awaiter(this, void 0, void 0, function* () {
//TWO NODES SEND IMAGES WITHIN A TRIBE ===>
let node1 = nodes_1.default[index1];
let node2 = nodes_1.default[index2];
let node3 = nodes_1.default[index3];
t.truthy(node3, 'this test requires three nodes');
console.log(`Checking boost messages in tribe for ${node1.alias} and ${node2.alias} and ${node3.alias}`);
//NODE1 CREATES A TRIBE
let tribe = yield (0, save_1.createTribe)(t, node1);
t.truthy(tribe, 'tribe should have been created by node1');
//NODE2 JOINS TRIBE CREATED BY NODE1
if (node1.routeHint)
tribe.owner_route_hint = node1.routeHint;
let join = yield (0, save_1.joinTribe)(t, node2, tribe);
t.true(join, 'node2 should join tribe');
//NODE3 JOINS TRIBE CREATED BY NODE1
if (node1.routeHint)
tribe.owner_route_hint = node1.routeHint;
let join2 = yield (0, save_1.joinTribe)(t, node3, tribe);
t.true(join2, 'node3 should join tribe');
//NODE1 SENDS A MESSAGE IN THE TRIBE AND NODE2 CHECKS TO SEE IF THEY RECEIVED THE MESSAGE
const text = (0, helpers_1.randomText)();
let tribeMessage1 = yield (0, msg_1.sendTribeMessageAndCheckDecryption)(t, node1, node2, text, tribe);
t.truthy(tribeMessage1, 'node1 should send message to tribe');
//NODE2 SENDS A MESSAGE IN THE TRIBE AND NODE3 CHECKS TO SEE IF THEY RECEIVED THE MESSAGE
const text2 = (0, helpers_1.randomText)();
let tribeMessage2 = yield (0, msg_1.sendTribeMessageAndCheckDecryption)(t, node2, node3, text2, tribe);
t.truthy(tribeMessage2, 'node2 should send message to tribe');
//NODE3 SENDS A MESSAGE IN THE TRIBE AND NODE1 CHECKS TO SEE IF THEY RECEIVED THE MESSAGE
const text3 = (0, helpers_1.randomText)();
let tribeMessage3 = yield (0, msg_1.sendTribeMessageAndCheckDecryption)(t, node3, node1, text3, tribe);
t.truthy(tribeMessage3, 'node3 should send message to tribe');
const text4 = (0, helpers_1.randomText)();
let tribeMessage4 = yield (0, msg_1.sendTribeMessageAndCheckDecryption)(t, node3, node1, text4, tribe);
t.truthy(tribeMessage4, 'node3 should send message to tribe');
const text5 = (0, helpers_1.randomText)();
let tribeMessage5 = yield (0, msg_1.sendTribeMessageAndCheckDecryption)(t, node3, node1, text5, tribe);
t.truthy(tribeMessage5, 'node3 should send message to tribe');
const text6 = (0, helpers_1.randomText)();
let tribeMessage6 = yield (0, msg_1.sendTribeMessageAndCheckDecryption)(t, node3, node1, text6, tribe);
t.truthy(tribeMessage6, 'node3 should send message to tribe');
const text7 = (0, helpers_1.randomText)();
let tribeMessage7 = yield (0, msg_1.sendTribeMessageAndCheckDecryption)(t, node3, node1, text7, tribe);
t.truthy(tribeMessage7, 'node3 should send message to tribe');
const text8 = (0, helpers_1.randomText)();
let tribeMessage8 = yield (0, msg_1.sendTribeMessageAndCheckDecryption)(t, node3, node1, text8, tribe);
t.truthy(tribeMessage8, 'node3 should send message to tribe');
const tribeMessages = yield (0, msg_1.getTribeMessages)(t, node1, tribe);
t.true(tribeMessages.length === 10, 'The total number of message left should be 10');
yield (0, msg_1.readMessages)(node1, tribe);
// Mark messaages as read here
const tribeMessages1 = yield (0, msg_1.getTribeMessages)(t, node1, tribe);
t.true(tribeMessages1[0].chat.seen === 1, 'last message should be read');
// check that we have less message
// mark messages as unread
yield (0, msg_1.markUnread)(node1, tribe);
// check that we have more messages now
const tribeMessages2 = yield (0, msg_1.getTribeMessages)(t, node1, tribe);
t.true(tribeMessages2[0].chat.seen === 0, 'last message should be unread');
//NODE2 LEAVES TRIBE
let left2 = yield (0, del_1.leaveTribe)(t, node2, tribe);
t.true(left2, 'node2 should leave tribe');
//NODE3 LEAVES TRIBE
let left3 = yield (0, del_1.leaveTribe)(t, node3, tribe);
t.true(left3, 'node3 should leave tribe');
//NODE1 DELETES TRIBE
let delTribe2 = yield (0, del_1.deleteTribe)(t, node1, tribe);
t.true(delTribe2, 'node1 should delete tribe');
});
}
exports.unreadMessages = unreadMessages;
//# sourceMappingURL=markMessageUnread.test.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"markMessageUnread.test.js","sourceRoot":"","sources":["../../../../src/tests/controllers/markMessageUnread.test.ts"],"names":[],"mappings":"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"}

View file

@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.decryptMessage = exports.getTribeMessages = exports.sendDirectPayment = exports.sendTribeDirectPayment = exports.getSpecificMsg = exports.getAllMessages = exports.sendMessage = exports.payStream = exports.appRejMember = exports.payInvoice = exports.sendInvoice = exports.sendTribeMessage = exports.sendEscrowMsg = exports.sendPayment = exports.sendImage = exports.boostAsMessage = exports.sendBoost = exports.checkMessageDecryption = exports.sendTribeMessageAndCheckDecryption = exports.sendMessageAndCheckDecryption = void 0;
exports.readMessages = exports.markUnread = exports.decryptMessage = exports.getTribeMessages = exports.sendDirectPayment = exports.sendTribeDirectPayment = exports.getSpecificMsg = exports.getAllMessages = exports.sendMessage = exports.payStream = exports.appRejMember = exports.payInvoice = exports.sendInvoice = exports.sendTribeMessage = exports.sendEscrowMsg = exports.sendPayment = exports.sendImage = exports.boostAsMessage = exports.sendBoost = exports.checkMessageDecryption = exports.sendTribeMessageAndCheckDecryption = exports.sendMessageAndCheckDecryption = void 0;
var sendMessageAndCheckDecryption_1 = require("./sendMessageAndCheckDecryption");
Object.defineProperty(exports, "sendMessageAndCheckDecryption", { enumerable: true, get: function () { return sendMessageAndCheckDecryption_1.sendMessageAndCheckDecryption; } });
var sendTribeMessageAndCheckDecryption_1 = require("./sendTribeMessageAndCheckDecryption");
@ -39,4 +39,8 @@ var getTribeMessages_1 = require("./getTribeMessages");
Object.defineProperty(exports, "getTribeMessages", { enumerable: true, get: function () { return getTribeMessages_1.getTribeMessages; } });
var decryptMsg_1 = require("./decryptMsg");
Object.defineProperty(exports, "decryptMessage", { enumerable: true, get: function () { return decryptMsg_1.decryptMessage; } });
var markUnread_1 = require("./markUnread");
Object.defineProperty(exports, "markUnread", { enumerable: true, get: function () { return markUnread_1.markUnread; } });
var readMessages_1 = require("./readMessages");
Object.defineProperty(exports, "readMessages", { enumerable: true, get: function () { return readMessages_1.readMessages; } });
//# sourceMappingURL=index.js.map

View file

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/tests/utils/msg/index.ts"],"names":[],"mappings":";;;AAAA,iFAA+E;AAAtE,8IAAA,6BAA6B,OAAA;AACtC,2FAAyF;AAAhF,wJAAA,kCAAkC,OAAA;AAC3C,mEAAiE;AAAxD,gIAAA,sBAAsB,OAAA;AAC/B,yCAAuD;AAA9C,sGAAA,SAAS,OAAA;AAAE,2GAAA,cAAc,OAAA;AAClC,yCAAuC;AAA9B,sGAAA,SAAS,OAAA;AAClB,6CAA2C;AAAlC,0GAAA,WAAW,OAAA;AACpB,iDAA+C;AAAtC,8GAAA,aAAa,OAAA;AACtB,uDAAqD;AAA5C,oHAAA,gBAAgB,OAAA;AACzB,6CAA2C;AAAlC,0GAAA,WAAW,OAAA;AACpB,2CAAyC;AAAhC,wGAAA,UAAU,OAAA;AACnB,+CAA6C;AAApC,4GAAA,YAAY,OAAA;AACrB,yCAAuC;AAA9B,sGAAA,SAAS,OAAA;AAClB,6CAA2C;AAAlC,0GAAA,WAAW,OAAA;AACpB,mDAAiD;AAAxC,gHAAA,cAAc,OAAA;AACvB,yDAAoD;AAA3C,mHAAA,cAAc,OAAA;AACvB,mEAGiC;AAF/B,gIAAA,sBAAsB,OAAA;AACtB,2HAAA,iBAAiB,OAAA;AAEnB,uDAAqD;AAA5C,oHAAA,gBAAgB,OAAA;AACzB,2CAA6C;AAApC,4GAAA,cAAc,OAAA"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/tests/utils/msg/index.ts"],"names":[],"mappings":";;;AAAA,iFAA+E;AAAtE,8IAAA,6BAA6B,OAAA;AACtC,2FAAyF;AAAhF,wJAAA,kCAAkC,OAAA;AAC3C,mEAAiE;AAAxD,gIAAA,sBAAsB,OAAA;AAC/B,yCAAuD;AAA9C,sGAAA,SAAS,OAAA;AAAE,2GAAA,cAAc,OAAA;AAClC,yCAAuC;AAA9B,sGAAA,SAAS,OAAA;AAClB,6CAA2C;AAAlC,0GAAA,WAAW,OAAA;AACpB,iDAA+C;AAAtC,8GAAA,aAAa,OAAA;AACtB,uDAAqD;AAA5C,oHAAA,gBAAgB,OAAA;AACzB,6CAA2C;AAAlC,0GAAA,WAAW,OAAA;AACpB,2CAAyC;AAAhC,wGAAA,UAAU,OAAA;AACnB,+CAA6C;AAApC,4GAAA,YAAY,OAAA;AACrB,yCAAuC;AAA9B,sGAAA,SAAS,OAAA;AAClB,6CAA2C;AAAlC,0GAAA,WAAW,OAAA;AACpB,mDAAiD;AAAxC,gHAAA,cAAc,OAAA;AACvB,yDAAoD;AAA3C,mHAAA,cAAc,OAAA;AACvB,mEAGiC;AAF/B,gIAAA,sBAAsB,OAAA;AACtB,2HAAA,iBAAiB,OAAA;AAEnB,uDAAqD;AAA5C,oHAAA,gBAAgB,OAAA;AACzB,2CAA6C;AAApC,4GAAA,cAAc,OAAA;AACvB,2CAAyC;AAAhC,wGAAA,UAAU,OAAA;AACnB,+CAA6C;AAApC,4GAAA,YAAY,OAAA"}

22
dist/src/tests/utils/msg/markUnread.js vendored Normal file
View file

@ -0,0 +1,22 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.markUnread = void 0;
const helpers_1 = require("../helpers");
const http = require("ava-http");
function markUnread(node, chat_id) {
return __awaiter(this, void 0, void 0, function* () {
const msg = yield http.post(node.external_ip + `/messages/${chat_id.id}/toggleChatReadUnread`, (0, helpers_1.makeArgs)(node, { shouldMarkAsUnread: true }));
return msg.response.new_messages;
});
}
exports.markUnread = markUnread;
//# sourceMappingURL=markUnread.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"markUnread.js","sourceRoot":"","sources":["../../../../../src/tests/utils/msg/markUnread.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,wCAAqC;AACrC,iCAAgC;AAEhC,SAAsB,UAAU,CAAC,IAAgB,EAAE,OAAa;;QAC9D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CACzB,IAAI,CAAC,WAAW,GAAG,aAAa,OAAO,CAAC,EAAE,uBAAuB,EACjE,IAAA,kBAAQ,EAAC,IAAI,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAC7C,CAAA;QACD,OAAO,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAA;IAClC,CAAC;CAAA;AAND,gCAMC"}

View file

@ -0,0 +1,22 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.readMessages = void 0;
const helpers_1 = require("../helpers");
const http = require("ava-http");
function readMessages(node, chat_id) {
return __awaiter(this, void 0, void 0, function* () {
const msg = yield http.post(node.external_ip + `/messages/${chat_id.id}/read`, (0, helpers_1.makeArgs)(node));
return msg.response.new_messages;
});
}
exports.readMessages = readMessages;
//# sourceMappingURL=readMessages.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"readMessages.js","sourceRoot":"","sources":["../../../../../src/tests/utils/msg/readMessages.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,wCAAqC;AACrC,iCAAgC;AAEhC,SAAsB,YAAY,CAAC,IAAgB,EAAE,OAAa;;QAChE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CACzB,IAAI,CAAC,WAAW,GAAG,aAAa,OAAO,CAAC,EAAE,OAAO,EACjD,IAAA,kBAAQ,EAAC,IAAI,CAAC,CACf,CAAA;QACD,OAAO,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAA;IAClC,CAAC;CAAA;AAND,oCAMC"}

View file

@ -379,6 +379,7 @@ function migrate() {
addTableColumn('sphinx_messages', 'error_message', 'TEXT');
addTableColumn('sphinx_messages', 'thread_uuid', 'TEXT');
addTableColumn('sphinx_timers', 'msg_uuid', 'TEXT');
addTableColumn('sphinx_chats', 'second_brain_url', 'TEXT');
});
}
exports.default = migrate;

File diff suppressed because one or more lines are too long

View file

@ -362,7 +362,7 @@ function getTribeOwnersChatByUUID(uuid) {
});
}
exports.getTribeOwnersChatByUUID = getTribeOwnersChatByUUID;
function declare({ uuid, name, description, tags, img, group_key, host, price_per_message, price_to_join, owner_alias, owner_pubkey, escrow_amount, escrow_millis, unlisted, is_private, app_url, feed_url, feed_type, owner_route_hint, pin, profile_filters, }) {
function declare({ uuid, name, description, tags, img, group_key, host, price_per_message, price_to_join, owner_alias, owner_pubkey, escrow_amount, escrow_millis, unlisted, is_private, app_url, feed_url, feed_type, owner_route_hint, pin, profile_filters, second_brain_url, }) {
return __awaiter(this, void 0, void 0, function* () {
try {
let protocol = 'https';
@ -391,6 +391,7 @@ function declare({ uuid, name, description, tags, img, group_key, host, price_pe
owner_route_hint: owner_route_hint || '',
pin: pin || '',
profile_filters,
second_brain_url,
}),
headers: { 'Content-Type': 'application/json' },
});
@ -406,7 +407,7 @@ function declare({ uuid, name, description, tags, img, group_key, host, price_pe
});
}
exports.declare = declare;
function edit({ uuid, host, name, description, tags, img, price_per_message, price_to_join, owner_alias, escrow_amount, escrow_millis, unlisted, is_private, app_url, feed_url, feed_type, deleted, owner_route_hint, owner_pubkey, pin, profile_filters, }) {
function edit({ uuid, host, name, description, tags, img, price_per_message, price_to_join, owner_alias, escrow_amount, escrow_millis, unlisted, is_private, app_url, feed_url, feed_type, deleted, owner_route_hint, owner_pubkey, pin, profile_filters, second_brain_url, }) {
return __awaiter(this, void 0, void 0, function* () {
try {
const token = yield genSignedTimestamp(owner_pubkey);
@ -435,6 +436,7 @@ function edit({ uuid, host, name, description, tags, img, price_per_message, pri
owner_route_hint: owner_route_hint || '',
pin: pin || '',
profile_filters,
second_brain_url: second_brain_url || '',
}),
headers: { 'Content-Type': 'application/json' },
});

File diff suppressed because one or more lines are too long

53
package-lock.json generated
View file

@ -4709,20 +4709,22 @@
"license": "MIT"
},
"node_modules/browserify-sign": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
"integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
"license": "ISC",
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz",
"integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==",
"dependencies": {
"bn.js": "^5.1.1",
"browserify-rsa": "^4.0.1",
"bn.js": "^5.2.1",
"browserify-rsa": "^4.1.0",
"create-hash": "^1.2.0",
"create-hmac": "^1.1.7",
"elliptic": "^6.5.3",
"elliptic": "^6.5.4",
"inherits": "^2.0.4",
"parse-asn1": "^5.1.5",
"readable-stream": "^3.6.0",
"safe-buffer": "^5.2.0"
"parse-asn1": "^5.1.6",
"readable-stream": "^3.6.2",
"safe-buffer": "^5.2.1"
},
"engines": {
"node": ">= 4"
}
},
"node_modules/browserify-sign/node_modules/bn.js": {
@ -5914,10 +5916,9 @@
}
},
"node_modules/crypto-js": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
"integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==",
"license": "MIT"
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
},
"node_modules/crypto-random-string": {
"version": "2.0.0",
@ -21141,19 +21142,19 @@
}
},
"browserify-sign": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
"integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz",
"integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==",
"requires": {
"bn.js": "^5.1.1",
"browserify-rsa": "^4.0.1",
"bn.js": "^5.2.1",
"browserify-rsa": "^4.1.0",
"create-hash": "^1.2.0",
"create-hmac": "^1.1.7",
"elliptic": "^6.5.3",
"elliptic": "^6.5.4",
"inherits": "^2.0.4",
"parse-asn1": "^5.1.5",
"readable-stream": "^3.6.0",
"safe-buffer": "^5.2.0"
"parse-asn1": "^5.1.6",
"readable-stream": "^3.6.2",
"safe-buffer": "^5.2.1"
},
"dependencies": {
"bn.js": {
@ -22022,9 +22023,9 @@
}
},
"crypto-js": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
"integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
},
"crypto-random-string": {
"version": "2.0.0",

View file

@ -14,7 +14,7 @@
"start-password": "USE_PASSWORD=true ts-node ./app.ts",
"start-hosting": "HOSTING_PROVIDER=true ts-node ./app.ts",
"prod": "cp config/app.json dist/config/app.json && cp config/config.json dist/config/config.json && env NODE_ENV=production node dist/app.js",
"tsc": "rm -rf dist/ && npx tsc && cp -r public dist/public",
"tsc": "rm -rf dist/ && npx tsc",
"dev": "rm -rf dist/ && tsc && cp -r public dist/public && node --inspect ./dist/app.js",
"build-binaries": "rm -rf dist/ && tsc && cp config/app.json dist/config/app.json && cp config/config.json dist/config/config.json && pkg . --target node12-alpine-x64,node12-macos-x64 --out-path binaries",
"start-ecs": "cp config/app.json dist/config/app.json && cp config/config.json dist/config/config.json && export NODE_ENV=production && node --max-old-space-size=128 dist/app.js",

View file

@ -178,6 +178,7 @@ export function init() {
{ name: 'Help', value: '/kick help' },
])
.setThumbnail(botSVG)
.setOnlyOwner(true)
message.channel.send({ embed })
return
}

View file

@ -75,6 +75,8 @@ const builtInBotNames = {
[`${ML_PREFIX.substring(1)}`]: ML_BOTNAME,
}
export const adminsOnlyBot = ['kick']
export function init() {
const client = new Sphinx.Client()
client.login('_', finalAction)
@ -105,6 +107,7 @@ export function init() {
const embed = new Sphinx.MessageEmbed()
.setAuthor('MotherBot')
.setDescription(botName + ' already installed')
.setOnlyOwner(adminsOnlyBot.includes(botName) || false)
return message.channel.send({ embed })
}
const msgTypes = builtInBotMsgTypes[botName] || [
@ -129,6 +132,7 @@ export function init() {
const embed = new Sphinx.MessageEmbed()
.setAuthor('MotherBot')
.setDescription(theName + ' has been installed!')
.setOnlyOwner(adminsOnlyBot.includes(botName) || false)
message.channel.send({ embed })
} else {
const chat = await getTribeOwnersChatByUUID(message.channel.id)
@ -141,6 +145,7 @@ export function init() {
const embed = new Sphinx.MessageEmbed()
.setAuthor('MotherBot')
.setDescription(botName + ' already installed')
.setOnlyOwner(adminsOnlyBot.includes(botName) || false)
return message.channel.send({ embed })
}
// bot from tribes registry
@ -155,6 +160,7 @@ export function init() {
const embed = new Sphinx.MessageEmbed()
.setAuthor('MotherBot')
.setDescription('No bot with that name')
.setOnlyOwner(adminsOnlyBot.includes(botName) || false)
message.channel.send({ embed })
}
}
@ -178,11 +184,13 @@ export function init() {
const embed = new Sphinx.MessageEmbed()
.setAuthor('MotherBot')
.setDescription(botName2 + ' has been removed')
.setOnlyOwner(adminsOnlyBot.includes(botName2) || false)
return message.channel.send({ embed })
} else {
const embed = new Sphinx.MessageEmbed()
.setAuthor('MotherBot')
.setDescription('Cant find a bot by that name')
.setOnlyOwner(adminsOnlyBot.includes(botName2) || false)
return message.channel.send({ embed })
}

View file

@ -212,7 +212,7 @@ export async function sendToStakwork(
},
body: JSON.stringify({
name: `${callId} file`,
workflow_id: 6173,
workflow_id: 12346,
workflow_params: {
set_var: {
attributes: {

View file

@ -30,18 +30,34 @@ export default async function broadcast(a: Action): Promise<void> {
const tenant: number = owner.id
if (only_user || only_pubkey) {
if (only_user) {
chat.contactIds = `[${only_user}]`
} else {
try {
const user = (await models.Contact.findOne({
where: { tenant, publicKey: only_pubkey! },
})) as ContactRecord
if (user) chat.contactIds = `[${user.id}]`
} catch (error) {
sphinxLogger.error(`=> ONLY_PUBKEY ERROR ${error}`, logging.Bots)
if (only_pubkey) {
const pubkeysArray = only_pubkey.split(',')
const userIds: number[] = []
for (let i = 0; i < pubkeysArray.length; i++) {
const publicKey = pubkeysArray[i]
try {
const user = (await models.Contact.findOne({
where: { tenant, publicKey },
})) as ContactRecord
if (user) userIds.push(user.id)
} catch (error) {
sphinxLogger.error(
`=> ERROR GETTING USER WITH THIS PUBKEY ${publicKey} ${error}`,
logging.Bots
)
}
}
if (userIds.length === 0) {
sphinxLogger.error(
`=> USERS WITH PUBKEYS PROVIDED DO NOT EXIST`,
logging.Bots
)
return
}
chat.contactIds = JSON.stringify([...userIds])
} else {
chat.contactIds = `[${only_user}]`
}
}

View file

@ -49,6 +49,7 @@ export interface Action {
only_owner?: boolean
only_user?: number
only_pubkey?: string
recipient_pubkey?: string
}
export async function processWebhook(req: Req, res: Res): Promise<void> {
@ -174,6 +175,7 @@ export async function processAction(req: Req, res: Res): Promise<void> {
parent_id,
only_pubkey,
only_owner,
recipient_pubkey,
} = body
if (!bot_id) return failure(res, 'no bot_id')
@ -209,6 +211,7 @@ export async function processAction(req: Req, res: Res): Promise<void> {
recipient_id: recipient_id ? parseInt(recipient_id) : 0,
only_pubkey: only_pubkey || '',
only_owner: only_owner || false,
recipient_pubkey: recipient_pubkey || '',
}
try {

View file

@ -1,31 +1,69 @@
import * as short from 'short-uuid'
import * as network from '../../network'
import { models, Message } from '../../models'
import { models, Message, ContactRecord } from '../../models'
import * as jsonUtils from '../../utils/json'
import * as socket from '../../utils/socket'
import constants from '../../constants'
import { sphinxLogger } from '../../utils/logger'
import { logging, sphinxLogger } from '../../utils/logger'
import { errMsgString } from '../../utils/errMsgString'
import * as rsa from '../../crypto/rsa'
import { Action, validateAction } from './index'
export default async function pay(a: Action): Promise<void> {
const { amount, bot_name, msg_uuid, reply_uuid, recipient_id, parent_id } = a
const {
amount,
bot_name,
msg_uuid,
reply_uuid,
recipient_id,
parent_id,
content,
recipient_pubkey,
} = a
sphinxLogger.info(`=> BOT PAY ${JSON.stringify(a, null, 2)}`)
if (!a.recipient_id) return sphinxLogger.error(`no recipient_id`)
if (!recipient_id && !recipient_pubkey)
return sphinxLogger.error(`no recipient detail`)
const ret = await validateAction(a)
if (!ret) return
const { chat, owner } = ret
const tenant: number = owner.id
const alias = bot_name || owner.alias
const botContactId = -1
const encryptedForMeText = rsa.encrypt(owner.contactKey, content || '')
const encryptedText = rsa.encrypt(chat.groupKey, content || '')
const textMap = { chat: encryptedText }
let recipient_detail
if (recipient_pubkey) {
try {
const user = (await models.Contact.findOne({
where: { tenant, publicKey: recipient_pubkey },
})) as ContactRecord
if (!user) {
sphinxLogger.error(
`=> RECIPIENT PUBKEY DOES NOT EXIST IN ADMIN RECORD`,
logging.Bots
)
return
}
recipient_detail = user.id
} catch (error) {
sphinxLogger.error(`=> RECIPIENT PUBKEY ERROR ${error}`, logging.Bots)
return
}
} else {
recipient_detail = recipient_id
}
const date = new Date()
date.setMilliseconds(0)
const msg: { [k: string]: string | number | Date } = {
chatId: chat.id,
uuid: msg_uuid || short.generate(),
type: constants.message_types.boost,
type: reply_uuid
? constants.message_types.boost
: constants.message_types.direct_payment,
sender: botContactId, // tribe owner is escrow holder
amount: amount || 0,
date: date,
@ -35,12 +73,18 @@ export default async function pay(a: Action): Promise<void> {
updatedAt: date,
senderAlias: alias,
tenant,
...(reply_uuid
? {}
: {
messageContent: encryptedForMeText,
remoteMessageContent: JSON.stringify(textMap),
}),
}
if (parent_id) msg.parentId = parent_id
const message: Message = (await models.Message.create(msg)) as Message
socket.sendJson(
{
type: 'boost',
type: reply_uuid ? 'boost' : 'direct_payment',
response: jsonUtils.messageToJson(message, chat, owner),
},
tenant
@ -62,7 +106,10 @@ export default async function pay(a: Action): Promise<void> {
replyUuid: message.replyUuid,
parentId: message.parentId || 0,
},
type: constants.message_types.boost,
amount: amount || 0,
type: reply_uuid
? constants.message_types.boost
: constants.message_types.direct_payment,
success: () => ({ success: true }),
failure: async (e) => {
const errorMsg = errMsgString(e)
@ -73,6 +120,6 @@ export default async function pay(a: Action): Promise<void> {
return sphinxLogger.error(e)
},
isForwarded: true,
realSatsContactId: recipient_id,
realSatsContactId: recipient_detail,
})
}

View file

@ -417,6 +417,7 @@ export async function editTribe(req: Req, res: Res): Promise<void | Response> {
jitsi_server,
stakwork_api_key,
stakwork_webhook,
second_brain_url,
} = req.body
const { id } = req.params
@ -473,6 +474,7 @@ export async function editTribe(req: Req, res: Res): Promise<void | Response> {
owner_pubkey: owner.publicKey,
pin: pin || '',
profile_filters: profile_filters || '',
second_brain_url,
})
} catch (e) {
okToUpdate = false
@ -489,8 +491,8 @@ export async function editTribe(req: Req, res: Res): Promise<void | Response> {
if (escrow_amount || escrow_amount === 0) obj.escrowAmount = escrow_amount
if (escrow_millis || escrow_millis === 0) obj.escrowMillis = escrow_millis
if (unlisted || unlisted === false) obj.unlisted = unlisted
if (app_url) obj.appUrl = app_url
if (feed_url) obj.feedUrl = feed_url
if (app_url || app_url === '') obj.appUrl = app_url
if (feed_url || feed_url === '') obj.feedUrl = feed_url
if (feed_type) obj.feedType = feed_type
if (req.body.private || req.body.private === false)
obj.private = req.body.private
@ -501,6 +503,8 @@ export async function editTribe(req: Req, res: Res): Promise<void | Response> {
if (jitsi_server) obj.jitsiServer = jitsi_server
if (stakwork_api_key) obj.stakworkApiKey = stakwork_api_key
if (stakwork_webhook) obj.stakworkWebhook = stakwork_webhook
if (second_brain_url || second_brain_url === '')
obj.secondBrainUrl = second_brain_url
if (Object.keys(obj).length > 0) {
await chat.update(obj)
}
@ -945,7 +949,8 @@ export async function createTribeChatParams(
meme_server_location: string,
jitsi_server: string,
stakwork_api_key: string,
stakwork_webhook: string
stakwork_webhook: string,
second_brain_url: string
): Promise<{ [k: string]: any }> {
const date = new Date()
date.setMilliseconds(0)
@ -988,6 +993,7 @@ export async function createTribeChatParams(
jitsiServer: jitsi_server || '',
stakworkApiKey: stakwork_api_key || '',
stakworkWebhook: stakwork_webhook || '',
secondBrainUrl: second_brain_url || '',
}
}

View file

@ -289,6 +289,7 @@ export async function createGroupChat(req: Req, res: Res): Promise<void> {
jitsi_server,
stakwork_api_key,
stakwork_webhook,
second_brain_url,
} = req.body
let { profile_filters } = req.body
@ -353,7 +354,8 @@ export async function createGroupChat(req: Req, res: Res): Promise<void> {
meme_server_location,
jitsi_server,
stakwork_api_key,
stakwork_webhook
stakwork_webhook,
second_brain_url
)) as Chat
if (chatParams.uuid) {
// publish to tribe server
@ -380,6 +382,7 @@ export async function createGroupChat(req: Req, res: Res): Promise<void> {
owner_route_hint: owner.routeHint || '',
pin: pin || '',
profile_filters: profile_filters || '',
second_brain_url: second_brain_url || '',
})
} catch (e) {
sphinxLogger.error(`=> couldnt create tribe ${e}`)

View file

@ -224,28 +224,20 @@ async function asyncForEach(array, callback) {
export async function clearForTesting(req: Req, res) {
if (!req.owner) return failure(res, 'no owner')
const tenant: number = req.owner.id
if (!config.allow_test_clearing) {
return failure(res, 'nope')
}
if (config.allow_test_clearing !== 'true') {
return failure(res, 'nope')
}
if (!tenant) return failure(res, 'no tenant')
try {
await models.Chat.destroy({ truncate: true, where: { tenant } })
await models.Subscription.destroy({ truncate: true, where: { tenant } })
await models.Accounting.destroy({ truncate: true, where: { tenant } })
await models.Bot.destroy({ truncate: true, where: { tenant } })
await models.BotMember.destroy({ truncate: true, where: { tenant } })
await models.ChatBot.destroy({ truncate: true, where: { tenant } })
await models.Invite.destroy({ truncate: true, where: { tenant } })
await models.MediaKey.destroy({ truncate: true, where: { tenant } })
await models.Message.destroy({ truncate: true, where: { tenant } })
await models.Timer.destroy({ truncate: true, where: { tenant } })
await models.Chat.destroy({ where: { tenant } })
await models.Subscription.destroy({ where: { tenant } })
await models.Bot.destroy({ where: { tenant } })
await models.BotMember.destroy({ where: { tenant } })
await models.ChatBot.destroy({ where: { tenant } })
await models.Invite.destroy({ where: { tenant } })
await models.MediaKey.destroy({ where: { tenant } })
await models.Message.destroy({ where: { tenant } })
await models.Timer.destroy({ where: { tenant } })
await models.Contact.destroy({
where: {
isOwner: { [Op.ne]: 1 },
isOwner: { [Op.or]: [false, null] },
tenant,
},
})
@ -258,6 +250,8 @@ export async function clearForTesting(req: Req, res) {
contactKey: '',
alias: '',
deviceId: '',
hmacKey: '',
pushKitToken: '',
})
success(res, { clean: true })
} catch (e) {

View file

@ -1,4 +1,3 @@
import rateLimit from 'express-rate-limit'
import { models, Message } from '../models'
import { proxyAdminMiddleware as pamid } from '../auth'
import * as gitinfo from '../utils/gitinfo'
@ -32,13 +31,6 @@ import * as action from './actionHistory'
import * as feeds from './getFeeds'
import * as contentFeedStatus from './contentFeedStatus'
const limiter = rateLimit({
windowMs: 1000, // 1 second
max: 2, // Limit each IP to 2 requests per `window` (here, per 1 second)
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
})
export async function set(app) {
builtInBots.init()
@ -92,8 +84,6 @@ export async function set(app) {
app.delete('/contacts/:id', contacts.deleteContact)
app.get('/latest_contacts', contacts.getLatestContacts)
app.post('/generate_external', contacts.generateOwnerWithExternalSigner)
app.post('/hmac_key', contacts.registerHmacKey)
app.get('/hmac_key', contacts.getHmacKey)
app.get('/contact/:contact_id', contacts.getContactById)
app.post('/profile', personal.createPeopleProfile)
@ -113,11 +103,14 @@ export async function set(app) {
app.post('/remove_badge', personal.removeBadgeFromTribe)
app.put('/reissue_badge', personal.reissueBadge)
app.get('/msgs', messages.getMsgs)
app.get('/allmessages', messages.getAllMessages)
app.get('/messages', messages.getMessages)
app.delete('/message/:id', messages.deleteMessage)
app.post('/messages/:chat_id/read', messages.readMessages)
app.post(
'/messages/:chat_id/toggleChatReadUnread',
messages.toggleChatReadUnread
)
app.post('/messages/clear', messages.clearMessages)
app.delete('/messages', messages.disappearingMessages)
app.get('/message/:uuid', messages.getMessageByUuid)
@ -229,8 +222,9 @@ export async function set(app) {
app.get('/tribes', pamid, admin.listTribes)
app.get('/admin_balance', pamid, admin.adminBalance)
// rate limit these routes:
app.use(limiter)
app.get('/msgs', messages.getMsgs)
app.post('/hmac_key', contacts.registerHmacKey)
app.get('/hmac_key', contacts.getHmacKey)
app.post('/messages', messages.sendMessage)

View file

@ -797,6 +797,75 @@ export const receiveDeleteMessage = async (payload: Payload): Promise<void> => {
)
}
/**
Either makes all messages of a chat read or it marks the last message of the given chat as unread.
@param {Req} req - The request object containing the chat ID.
@param {Res} res - The response object used to send the updated chat information.
@returns {Promise<void>} - An empty promise.
*/
export const toggleChatReadUnread = async (
req: Req,
res: Res
): Promise<void> => {
if (!req.owner) return failure(res, 'no owner')
//
try {
const requestBody = JSON.parse(req.rawBody)
//We want to mark the chat as read
if (requestBody.shouldMarkAsUnread === false) {
// Call the readMessages function with the same req and res objects
const result = await readMessages(req, res)
return result // Exit the function after calling readMessages
}
//we want to mark the last message + chat as unread
const chat_id = req.params.chat_id
const owner = req.owner
const tenant: number = owner.id
// Find the latest message that is not from the user and has been read
const latestMessage = await models.Message.findOne({
where: {
sender: {
[Op.ne]: owner.id,
},
chatId: chat_id,
[Op.or]: [{ seen: true }, { seen: null }],
tenant,
},
order: [['date', 'DESC']],
})
// Update just the latest message found in the database to mark it as unseen
if (latestMessage) {
await latestMessage.update({ seen: false })
}
//mark the chat as unseen
const chat: Chat = (await models.Chat.findOne({
where: { id: chat_id, tenant },
})) as Chat
if (chat) {
resetNotifyTribeCount(parseInt(chat_id))
await chat.update({ seen: false })
success(res, {})
socket.sendJson(
{
type: 'chat_unseen',
response: jsonUtils.chatToJson(chat),
},
tenant
)
} else {
failure(res, 'no chat')
}
} catch (error) {
return failureWithResponse(res, 'Invalid JSON body', {
error: error.message,
})
}
}
/**
Updates the messages in the specified chat to mark them as seen by the owner and sends a notification to the other chat members.
@ -855,7 +924,7 @@ export const clearMessages = async (req: Req, res: Res): Promise<void> => {
if (!req.owner) return failure(res, 'no owner')
const tenant: number = req.owner.id
await models.Message.destroy({ where: { tenant }, truncate: true })
await models.Message.destroy({ where: { tenant } })
success(res, {})
}

View file

@ -148,6 +148,9 @@ export default class Chat extends Model<Chat> {
@Column
preview: string
@Column
secondBrainUrl: string
}
export interface ChatRecord extends Chat {

View file

@ -22,7 +22,7 @@ import { logging, sphinxLogger } from '../utils/logger'
import { loadConfig } from '../utils/config'
import { errMsgString } from '../utils/errMsgString'
import { getProxyRootPubkey, isProxy } from '../utils/proxy'
import { ML_PREFIX } from '../builtin/ml'
import { adminsOnlyBot } from '../builtin/mother'
import { Msg, MessageContent, ChatMember } from './interfaces'
import * as intercept from './intercept'
import { typesToForward, receiveCoTenantMessage } from './receive'
@ -543,11 +543,37 @@ function compareAliases(alias1: string, alias2: string): boolean {
return match
}
async function updateMessageToIsOnlyOwner(uuid: string, tenant: number) {
await models.Message.update(
{
onlyOwner: true,
},
{ where: { uuid, tenant } }
)
}
async function interceptTribeMsgForHiddenCmds(
msg: Msg,
tenant: number
): Promise<boolean> {
const hideAllCommandsBot = ['/kick', '/ml']
try {
const content = msg.message.content as string
const splitedContent = (content && content.split(' ')) || []
if (splitedContent.length < 1) return false
// must be a "/" bot command
if (!splitedContent[0].startsWith('/')) {
return false
}
if (splitedContent[0] === '/bot') {
if (adminsOnlyBot.includes(splitedContent[2])) {
await updateMessageToIsOnlyOwner(msg.message.uuid, tenant)
return true
}
return false
}
const newChat = (await models.Chat.findOne({
where: { uuid: msg.chat.uuid },
})) as ChatRecord
@ -556,8 +582,6 @@ async function interceptTribeMsgForHiddenCmds(
where: { tenant, chatId: newChat.id },
})) as ChatBotRecord[]
const content = msg.message.content as string
const splitedContent = (content && content.split(' ')) || []
for (let i = 0; i < bots.length; i++) {
const bot = bots[i]
@ -565,15 +589,11 @@ async function interceptTribeMsgForHiddenCmds(
bot.botPrefix === splitedContent[0] &&
bot.hiddenCommands &&
JSON.parse(bot.hiddenCommands).includes(splitedContent[1])
const isPersonal = bot.botPrefix === ML_PREFIX
if (isHidden || isPersonal) {
await models.Message.update(
{
onlyOwner: true,
},
{ where: { uuid: msg.message.uuid, tenant } }
)
const isDefaultHide =
bot.botPrefix === splitedContent[0] &&
hideAllCommandsBot.includes(bot.botPrefix)
if (isHidden || isDefaultHide) {
await updateMessageToIsOnlyOwner(msg.message.uuid, tenant)
return true
}
}

View file

@ -4,24 +4,75 @@
"pubkey": "03a394d0ebf0d003124ab130c6b12b8b990a50a30a464354800a51981ba745bb07",
"ip": "http://alice.sphinx:3001",
"external_ip": "http://localhost:3001",
"authToken": "f0M3tvwpiH9BaXAhLkA7",
"transportToken": "MIIBCgKCAQEAmwXF6+EAD0+8Bh31IMd//Hn/+35303tON3gj+WTMQz7hfjAgM91o\n7z8LSoRzX2nORHs9/vKMG2hcmKfaOdmS+rjQcOVPVddCvI0qCzh/Y0lVRHes8Nlf\n/xu+QXdWs5i6z//X6Ek/6AsEKobvdB8Ac6vlrEKh8QIk7+Nd//j72sExxmWPhe2z\nbBNKTuFKfcs9/KfSEOCTSGJCA2d4NCKfOYRltQyx6baLZ7gGxa75ZA6mEQisJcQ/\ndmwrZ3KhvnQqN35rWbKQsfr74K5ds0uK58wWfjnLGNmySbHBNgWQhqt7CV/m6kGf\n5D2nx/3hcBnGEJWaXIX1frMb0l5RnLEqlwIDAQAB",
"contact_key": "MIIBCgKCAQEAx/IJ2/Oe+IK2q59g2rqLP7anW/4rGMDCPgPjUt8G4qX7IIxoSGQPt3KKw9f6LVIKITGDo/KfftynV3ea6oDcPU01hsDnaRKJJiazrO18k5VzwOqTVm9CsyXZdbLL7oOG26M3ivr/G2xM4earBab/etPHOowYm/Gm8rIscha+WvowliSE3jqXHBAktcdMLsaa+e7AtJ5cQ2vlwU/MuZPidx8vHQXAh2L1Jvu4WvPFAX9uUSFBQeXxpfgOH8jfMKyF7bPRf0uaXKAqWO/vJD0me8tc+b0eu8qn8GAwaT+KVgEMZiEj8koh6GluLbQTd6BNSZDS6dhlbNmNCWuhuSmsVwIDAQAB",
"privkey": "MIIEpQIBAAKCAQEAx/IJ2/Oe+IK2q59g2rqLP7anW/4rGMDCPgPjUt8G4qX7IIxoSGQPt3KKw9f6LVIKITGDo/KfftynV3ea6oDcPU01hsDnaRKJJiazrO18k5VzwOqTVm9CsyXZdbLL7oOG26M3ivr/G2xM4earBab/etPHOowYm/Gm8rIscha+WvowliSE3jqXHBAktcdMLsaa+e7AtJ5cQ2vlwU/MuZPidx8vHQXAh2L1Jvu4WvPFAX9uUSFBQeXxpfgOH8jfMKyF7bPRf0uaXKAqWO/vJD0me8tc+b0eu8qn8GAwaT+KVgEMZiEj8koh6GluLbQTd6BNSZDS6dhlbNmNCWuhuSmsVwIDAQABAoIBAQCQ0Op5J4ONhMcfmMkCwzfWBspCo929COfnGNPOEwEeqY8w7OEfBXIosUp2PHjT2GbD0eQBm9oPfWuqu1M14+0gbUqGdjNlc+pn+oIKjtu63PVA1eWvJdiOfqx5Re3Uq+jCLf4tqEubJh6tQ2+9IU5LPRZAfnXYhPchMxFj9Lsckm5hXIP9UGgPnNv/uPN+IR6I/i4z5HHCHTKVkiIwlIY6Ps1o2WvnuGz8+O8ghhUM3b297Ff466OGZ37j4Bx7faOPCkI1f6YZr7oyStRZRQmYHJHj3QdVvaQ6h06SIZMgNMZVd9jBZbVeyi2TXZ/GN7Don8G1GbpWLWW0nbE36wtxAoGBAPSdrf2M6j/ay/R+/ujFej/UWlZC+I91UULgKUWpElDovJDVMm2VWb5Wt5JV9kvsDdk3+9D4252hgKJT7z82gmEvWk9MzYY9mEdEhAO1bGGWiz8/D0Prm5iVhW7CzAfQ19WsXbU0FSLX+KT6wrsOBJICHvX550Tg9/O2tlsM2QAZAoGBANFAKTnE+YYuZrvn80jrXP71uiw0reAkZVQePxWPb+bD0jNS+AKQarsCkFUl/BbXVMH84UIRww3r6Tor2BHaEELdzcu9kXgp5Mh/GW1I79RUgZ3lkmQyKwEjMC3bf4ZJKtbw08R3iCDyd60vBVOUwGefhfTV3QNx8lnUIIgtBd3vAoGBAN00rj/Iq5j9Ak1ifp/+3NNV9C9ntqD8hXTFg20kPJUAMm2C7mxcj+BpSO5DYEw99jQFxWmvceJ1Rv8EiikO4Q6DpNZrbLxFfSyNkBhOeukxG1EhdGuGZ5mvNQ/5hkpXGKd4jPEtXSO6THbc8TX4sjdbRaZIzFPkYTV6eCOUVbQZAoGAALmLKwMOpjNU8cOs6Qy/prZtLagFDiiyHSd5qnZzucXl3X2lFEUxyXIJ0/GsvNuEFKPul8798PdnOGdceTtbIRApnVILxfHHNBaUnPdKtV6RkF1yM1ylH3zittXyzCFGv7XX1e9gDlUoqvXlu9NhEzrPOPjgqhlj8IG2lyIoygsCgYEAmqIgGM76umea9HX+mIdLNJ5hsjyn0ZwYc/x0nrvqbgqkx+5ho76A/BmbS94CUVKVMPxcMtsHDNxpkEogau6kD95ImD72YMy8hOB282LmC3DSoUNRbqg8joh8La66UNgRavt34OEwaaLaO7+TZG6Q3IOkKa2TolWlm1AUDHJEujk=",
"exported_keys": "a2V5czo6QXdFaXdKbms1NFNZam1JSng2RjZ1UGhmbHJHSGxUR2FIQjd5eFZ0dDVKelUxM0hidjFUeDZRNXR5eG9vVFlxZVcrUTd0MkttbGkxeHljRE45WVFpcHp6ZjBXV0NGckNhdXQxd1kySG4zNHdzR3NVd0dlbVdiUVFxc1JkbE5WT05YaGxoRE1KZFF1Q01KdVNTci8yTXNDOVpFWmJXeTRCRHVPKzdyNXBmMURUaHQ1LzFTVXYxbWJjSCtvcndMQXZyNzdxQ1E2WUJFN25aYlNSVDdKWnZQMDJJWnpISncyWlNIOGkwMVNBUnVDdlViMkhDaTJ2OXNnKzB5dlNDQmszOVBPZzRNcFZrY3prMHhZa3VqVWYvR1p2dFNJNFJmM1lrVFJPazJOdXYrWEgwcExGZzN2bHFXWktUQ3FKbGsySTk0YWFaUGp6UElTV0hWaURDODRReXgwVXlKcnltM1hiOFY0ejBndlp4Qi9CUGR1ZVc5MURWdUt6NjFLc1AwbHkvMHlRaWZDOHpYVk1ydEgvdGNRQUtYK1hUQ2gzQ3kyNHVDYVF2Z0RDSkxpanY3NFFKWFJNckJ1MzlTUGFOMEpveVVDUkxiTmwxMGdUZ2NBWFF1aVJMaTFBcG5OdFcvRDVsVGtoMUVSTkI4aGYrKzBtMEtRZGNZQ1kxV3F4enV6cmgvMG1XOGpIM01XQzNSdnJCd1ZYNzVUaCsvTjJHd251ZUhEWU1FSExLVGF2cXJXZWpvL2FWOXFpWC9HUEJqZEk1Q2Q2RnF2L3I4aGRBUTFuajJ6LzYzOXIzdFR1YUdybkpvRlIxR0RtcDY5MjV5VU1pak9pTTVlNXJYNkNWSW9TYjV6aG50K3h1ZHBzN2QwQk1Wa2ZZSU1qZ08rS291bWhXZ2ZydHlwdnltbVpjRWNvdW9WRUZTdFB2blNHRi9BbzF3aDdmMWRkbEw5VzBDN3U0N1ZncFByMGp5bksrSE80aXI5VzR2YTk1NWpSYXk0bjlnNWI3cVh5d1ZWRE5IUXFOdEZ5TWpQaHNzWGNIck14ZExXaUVpblQvK2NLYXVXQ0xRSnB4dGtwSDVCVjNDWGpQUlNsRENIa2xIR0JwTXhzZmVCdHpjUzBTeGVvVjJtVGp3Uk9VcjBuSW9JdCt5SXQzUUc3NTk3UXc1eFpVbnorR0psaE9PMmg4TnpXZ0hXT2pPYzBSZ2lwSm5vZTNKZXFuWjZUeWI1czRYVWhGWmpPMmJsSTdvUll2MzZTWGZiQnViOXdEWVFzbFZlOXc3NjdLUUtEMnJWU2VXMHlZeEJMSENiYnB6REJydys1WnFMZGUrdjU3eVU1NFNyUmtFMnF4dXRhTlh6WTRXYUUrQWFoRG80NlVTUlQxYStLM2JxK2RIemI5L2dRWTJNeW1uRm90cTV1eVRjSFMwWmc0ZHo3Uk5EZUdDMU9qUWk5akptQmZ0ditXRWEyTlBzQWg0WXd5d3U1TUtZSmJIY2FSWWwvMytkOTZFY1RrNVRKaUxPR0NxL1ZVT0JOQ0ZXMjZEOFB4Zmg0RWJjV1VUWE5LMitocER5RnpWMGVPc3IzWU85VlVyczdQVXc4VER3TklBY0IwUmIxNzZPMWp5b2lWSm1UUjlVNUlsRGxBb1BrcnhrY3FOWTQ4MElxMDY1Zi8yb1BFNURTQVkwQTFqTnFpVEpUYUg0aEFlcjk4WXZ4OG1rWml1TEl0VVVGYnVXSGhGTEdzSEpwWEJRMjZJL2pYMTcrQzBadlFtUDZjZ0dra3VXbU94ckxqbkI4R1NBakllVXZSVitOMGVndXY3ajQxV2dmZk5rTmZUaGVkZUdzNEQ0VHlLaWhjOVNFcjhqQ29ZK3RhTEcvTHllMmkrbHhNSWl1Y3BabG1KUjVkQ1FaVXpzWGdjL2h6VHZTbGpvWjBZVUhsY3dod2ltRkl0OTUvaDFIV2lOakw2S3JNenRJcFVxQmJGQkZxOUJTTGtzR3pOSFIzbEdZdkNPYnZxMG9mSFZ5TUtxaTY5NE4wQXZIT1d1bS91bjR0d3hnd1V3V3VNUE5KcDVjTWVtVWRBckVjRzR5RDRlOEJmWFhLc3BUSmtxeXMwVW5vQzhCbFF3OFd4T216dWF0dXhnYjdsSjJtbVJnOG9NL2c5Y3dVMVdoZDUvc3R4Mk5OYlgyTnl0TmdwdGdZZ1pkbkRXTE55SHNUSHVTWnVOV3JCYmJydEM1WnQyME1yOG9xZVlFdTlINXpXWVJtY3d1VU9QVm1DZ05lZStNZndkTVE4b05DYzNWWlpxV2VYSkYrSzRtQnZ6TjQ4UGJKNm5FdWR2Rm1qZGQ1b2RJVlJ2OGdOQXB2WGdMZGR5K21GRFZZZzg3UkxVMlpqOW4yUXFXMGxBeVZqTkVUSTZWY1k4SlBobUg5SEErclRYa21DWDZEN3RIODVEbk9hRjAyajN4OGpLY01SQWU5ZFNQbFBBUW90cEVqMUEvYzRvQ0kzbklwMlo4b2hqK3F5bEw5YUFYWHp5WGJ5WEk4MVBsalZ5dmQvL1ZmZU9WQ0tBVWpsRU5oeWRhZm40SitRS1B1ZXRrMkY3Um5sczVIaGozVC9Xc3FQYTFDelppQ2I2bE1icEFyR2d1OHpjbnlFOHhqWkNYRDNPcUwvS2JVMTd3NkxLV24zWVFJaHRFRkVtWkJxUzVvai82TTBTRURhaDdObmxzbDFXd0tEQ2hYQXFEbUlEQXp3OVJJeUhaUkk5UFJ3WFlDOUpTUzlkK2M5K3ZJK0Z2STlHUHNOWUxaT2hqUnBEWDBESkdpRHY2T1RXczNydDRqay9nNXU1L2VSVUhPaitLeTFUVkg2RjRjMmcxL3BMTmFaM3crTDFIdHYzd0xGc3RiSWM1RG1HcGJEY3VaSHlvY013a2tpdDFzMXJFQmJacUxXN2ZORWVENGVHeFRYM0craXY4WllaUWx2TEpyNkVJV1ppNmg2ZUIrT0txYUFzUGxPaCtKQUU3c0JLVjNpc1VLaXBYV1BQMmdGT3JPbkFydFA1MFRwVndCQjdTV2RJdWJwSGtzOFhYLzVtY25MdmwzVEZaYVN6NGphOHNrRytuZ1pvdklWR1pBcUZNeVVqclBjVHUvaUI4RVRyblhpMW9sR1FyL2RCNUVtSzNZVG4ybWx0cmNNcHBrQlpWYXNJaFlBbWFNMytFQWhBNW0wQVhuRWZhcmFOZDZSc1FRbG54b2RYKzhMWGx2d241U0tENWNFUEkwcEdac3ZYemZUNzMycjJ2TXlOdWRpdWhVZ2p4SGZWY2g2WnF0RmYxTmNITXd4NCtsWkVlaHorWWUvU0lvRGNjMlQyRHExZFZ5eUFIUmp4V1VRSFdiWlM5Wmx2VFN2MmRjL0ZrcW90VlVtVEFxTkVOclVQVlQ5L3R6MzJPZ09pMU95U0lNMFdiRDFuRTkvVUwwOThlOFdpVE5VNTAyMmswQ0wra3dCTUpUSzFHNG16Y2dnVXdvN3ZPcTVEaXVBblcxN0xjSkZac1RZYXMra1pJYVZjVGV0ejYvMVE0NG9TSlRxMVM0QjZWY1hZbTdiNDVteDVPTXdvNXhER04zb3E4ZE1YRi9BbjZ0c0tWdDg4NkU0MXpJNVV1bVY5aTNCMVNUTWhmZW9iQ20rZzJjTlZ1aW4vbEx0Q0t3cTFNaXhaTmZKYk5SVzlxTFBUQT0=",
"authToken": "N68QcZg9WENR/ANiik9V",
"transportToken": "MIIBCgKCAQEApLzAOGM6GyI0cXmeLuak3Jp9i6NvwThQVBpQn3RUSwOVX0r3As23\nXJmgn4bsLZrj8SBb6ENEAZIi1Bf9tFP70EV5ckQQDYE5cmzJQVuYbbXityftdsl4\nXWdq8rat3GwrU1GsF24tFFyX9V1dU8qLOPrcp4/WsjzWl+trrMYIfV1XoCuGHITl\nosQ+osIy/LiHj1TE8OkPUiWVRGaqDeZ87yH1HRrYAfvcT8megaCAaP3ETI/PkmkY\nTUDrn51oew469fa1reg6FqemDbbUciBdXqOcn9D6JF6SOzm0lNPBRMeE472D+OY5\nU2y06nNYM0I8w+02z/nowtgaZ9P3yRd00wIDAQAB",
"contact_key": "MIIBCgKCAQEA29Rbw2heWdzB+mYG6It/E8oJxgQh1yRi3Zi2T2EtpfRiN10G8Asznl9UqO6fSK0omCC6V+eGp07fVga2vOPekfMFJkG6AF5EqbpdSmWvCLU2vzVu7W1/0dgqoYlz9cQzyIYG3LM608tAdAX9SfjeUzT95rdy6m4JVG59MzUkv6F53rk74hYcgzxxzhkF7W0sgziQc1FcwMb1Dh9bPHNvlOZ/EA+gM5xoDCHR1ygvQ8DLy052MjgP7WjEZtwvFIEU5pJo6RnYaavI+XarH5+blI7o5GAQjJDWRDV2wtaPN438FPHrw9hTFMV+XNik6Af9st4LGO7BRwiptfsHXJDb1wIDAQAB",
"privkey": "MIIEpQIBAAKCAQEA29Rbw2heWdzB+mYG6It/E8oJxgQh1yRi3Zi2T2EtpfRiN10G8Asznl9UqO6fSK0omCC6V+eGp07fVga2vOPekfMFJkG6AF5EqbpdSmWvCLU2vzVu7W1/0dgqoYlz9cQzyIYG3LM608tAdAX9SfjeUzT95rdy6m4JVG59MzUkv6F53rk74hYcgzxxzhkF7W0sgziQc1FcwMb1Dh9bPHNvlOZ/EA+gM5xoDCHR1ygvQ8DLy052MjgP7WjEZtwvFIEU5pJo6RnYaavI+XarH5+blI7o5GAQjJDWRDV2wtaPN438FPHrw9hTFMV+XNik6Af9st4LGO7BRwiptfsHXJDb1wIDAQABAoIBAQDa51u9ebfCyncLjv/AH/EaVq1m1wSPxbcBramV4FJhmLsZIHThInZzdcDLPFu3Nl9fJfAJyw8mmf8CHktoS41+Tr7I+thqt3Sug1uU0y76f+GVhHMC0XBgGV9SXprvmEJsozJAIeYps5NqNfCk8cMKnpFbZ0Byu8JkpmXcUUZX3242x4kYGxk3npnxPN6W7Jq57RN0FIKIj35mu7naPV8V5jzcA/7hRsSJcNdCxFNSDmK9qLow6rdutAZ2AmlHBSLgL/46rGpwKPbGs6RiuxqwMj4NG/KjDmFjy37Me3Le2SHQ9hEzBtO2vfmLW85V8nyEPyemQBYOZn1/ErCnuuDZAoGBAPv8IAKyDloKPoHGFuURPxJexwmGKcJ+R3XYf9D/VB0w2UZM112Arz8SrGboTUeN+joUdvTO4Oxi934nALSuikPc4pOfiMIx6A1EW+sl7c+c70vJwBV/KQWUc/nQIPvIVigzC7rr8RF+MUJI9C8j+InXM5NB1VCVL20KbWx0jKSdAoGBAN9VEXBzwVF65SnbSUZ1xueiqE5kRJfJxcjAZXxKLB3PTBqNg7bbbwaqZRu2JWalwKaPMHETLBz494tSBR3XGvDypDViINODiLlh8P8JD9CLPUEyi61/FutXNn0J1CnwmM5k6Qq+4lqU27KO1SymxCmEErPqOkCivHTbWMJpCEYDAoGBAL5td+dxliT3but1vuGXmfmRBIuvByoDco+dcGKKQo/Y1aop8euoj0d0HjOaxKQZqItx4b/6A8LAu9ZrNT5WVQkaCWSUgK55NquoCGr5e/GU4MZ+jhnwwhiEauzUG8kLSgkRIoE9Qy38Fs/IADkLzwykREa5zrIaPAAEjFMU9SCFAoGBAKkuGg3jwnhk7qCsm2+i3NCwKWtpDYUmtouDI93pmk3isTYUKcklpY+ZGQrLCr4dpjkGk5209l/kQjHqKjIWtzP7u2UtNszEAZjdluC8DpzePcLb9W+yrLwOzxodjflPZ5JCYz9epr4TsfIrvVUb59HDWR+tuf8oyDaFy1FKm5fdAoGANfzrlKSQ38hhi/0CtNUOba6+4t6TU/geLyqOjUD/VlYhz0qPmd55uOPHldqxnc9WHIG+mh8QhXTIffoMpuTtFuoGwe1W7zCPaBF0NTig+B8xXUNGjjWNFDq9sWEK8sPQGwLeC7w+w4bmUS18Jyo6wXoRdEiIRq+j7tdLL/Wdjrk=",
"exported_keys": "a2V5czo6QXdHRmNjaVdmbVZzL2poVDgyYUF0RDUyTHBDUUNLUS83Y1ZITjQ2elA2a2t2VTJNTXR3ZE55ZDdlK3hCeDI3d2xjUkpOQWhsKzkvYlp0WEtlWDZnVmVoMFhueFJ0bE5NVWErWmV5RWprVExlbTkzZXJ3dWpQa1FBYXNaNjJLaTdEb2pDKzVkcVhySzdaT3JwQ0JqWTRwQURjNk5zL2FKZEQ1bVR4Zkc4UWZTSG9mZmprRWQ1KzRVRmdpUkpXbnNNdzkzbE8wU0dyK1BJT09FY0MyYTduN2dZNFl5QmpHOUY3SElLVWF6Y2l4QjhxUFRyZVhOd3VVVjFvVDJqa0RYOUxSVEtBeUNJQTV5UmJpY05HaU5rVmxkRWdiM3pWMjVja0d1ZUM4TzB6MmtEVUlPK2xHZktxMERZY3E3K2s5NTdLcDNaN0hHS3FZelFlTWsrVTFnUXZKaTZWdThHbDdIMUdUb2MxT3hjMmxJS0luMGZaSmlYN1hzcGwyaUEzTEFqbWpFVWJBSWozTGFsYTFWLzdqOFdLRWthT2llckUwcFZ5WU1lSENUOTRaNWxwYWYxeC9lQWtEUXdaelFYeVM0d3lTK1hsWnJKSGs5WGlQeVJXZ1Z3V09ERlB0RldJT3Y2NXFZL2laUCtpbTFtOWVLUUpGME50RjgvRmU2dFpjWjlRQm9xdFRZenJKYVZiMStDZi9OY3RYQVk0UnJNRlhObVMyTG9GV1p2ZFRmNU1tSyt5SFo2SHBCQkwzdkZmMC9LaXhGSUpBT2x4WHUxU3FiZlg5WTFVN1B0Q0F4K0FaNDJiSVZIUDV0M3kvK0dCVXZleHl1clVVenp2N1VGY0hJVjI2TTc2R3ZGUkpIakdJbEx6ci9RWEY1blZOMWYvb2psRzkwZ0Y2azNGZWM4QW90TXFXbDdsMENyOWxFRGNxUDlpMFJaSGdoeVpnamJzcGN6SFRKSFNjclpES2ZWbDkwVmdJaGRZenRaZFI4YTNkMTByRjA2K09QWWJDUmhXZ0pVOHBSZlpKVlJ0WVZLVnN0dGtCOHNkWUJHcUFjNnJ1Vlg3SUNKbWQ1eWY2MUV3bG1mTko5Y0FIaGN2MEcvbHRIb3lvNUZLNlZtODVwWWRNdzFtODI1djRUY1A4emRQVTNvanduWHlUUkhUdTYyS21kU09xOU0zZUR2U25RT1M1bDVxU2dGYVNGdDZXWC9teldYN2ZzcUlCdjFidU5oR1I4THdHK0lWdjJaSWdwRlhEcjVyS0VaUFRPYlZucHZLcUdDL253M04yZHAzTHpXUVJzSGRyejJUSjR3VG5kdS8xRjZtNVhVV0xuZVEwMmJmZ1JWRkd3LzlzUHd6cytVTFFGN3BNOCtaaEd1WUkrckpybUNxMDRBZ1R0NFZ1WUZFSFhyKzkrbnliMlFJNkhGQ1IxZTF6U1crT2NFYU83ZjYyMmdEZEcybFpEemxVaTVMMEp2SG9Zd0ZUUVFrd25uRVBFT1JNdlY5enhtUWo4R0xZMGRBejNIdjFJa0RxSWJyYTJqV0ExbFlUOFlUV2pzdXJxUzFyNlp2MkZhVDdCaUxqd3FFWDVVc3JGdGNVUnZjWEFPaFI4bjY3L3Y3cldwcG00WStKYjFENUowMHZHV2x5RHFtLyt2blBuYnludE9ZMnppdGhONnM3bTdNcVBaUUlXZkEycTRWVFFXTWxTRkV6MzRvaGtzSUZRNVVrN1ZvTDl0SVlSbXZXQlhXRENhTmdGTnBXeEdVMHJtakZwbkpIOE9URlI3aS9YY0NMQnJ0OFdQMno3a0lram1ZeU1nQ2FLT1Y4NzZMVkZWejN5Y1hCQ0JHZ1NPSWdHeU1ldWR4c0FOam9vOTREci9qTkJKL2lrVER0b1NrVFBOZ3J5aVRSbDJpdWZxN1RJZ3FJK2laUVF5RHM2bWx4MmJ0OXZzRGhQeU8wSWozS01zQzZVL2pJYlN4MlZUeThaMjRVUVBoQjRmazRkbTFJZGVVWTJpaVNYTHlPcWRMYVJTYU1LSi9RcEFRbVpKMENVSWpNM1Y5Y3VnQThEV2hQZ0lreHZzTGFtTldGMnNyZUs2eHI5RFVwL1g4N0h0Rk9lZ0pPQVRzTTFmN1VsYURXZUZpYXU5eEE3ODEwU3JCM2twUjdlcHRPcXFURUV6MDdJZ21IeHROZytrRFFtWEFidUlQZWE3QXlVRkFVTDV2ZFNibXlMNU96Zk9ENy9lQlo3OXQySGRTMy91a1BOZ25lTjF2Vk90amwrMkFSNVRLUE8rQzZGYy9BT2NDNFA2QXBVZE52eG5tdDBYTkorNm9CdnEvaTFudVF1RkVBTWJsVGVmN1N6dVI3TTF1TEVhekdHSUplSkVpeTFGazVpWEozOTRTWlFmYVVXZU9adUlzTkdyRWxEVnNEMlpFVldwb3oyV29seDh6ZGVzOXQyQWl3U1VQS1ZvQVl2R1Vya1U5OTJTeDJlVEdCOWFteEZtSi9jVkYxOGh1T1JCUjRuZkh3VjgzdmR5bmJ6SmJHYVZPTFZwbUhmWGprY1JzWkJqY0pNbnpRUCsyQk1lLzBEcVlkMjUyeVI2cTlEOFZOOEx2V2tjcUVud0JYeFFSY3V3emFzaTZhWnh4QmJmUjlTZ1l2L1l1V0xnNjQ0RUswYzdYcXMxeHdNY3pqMjY2R3lxcHdlWGYrY2M4emxvNVFHT1o3QU4vODhMUjlZSmVqcjdYSHpTWk1HQzA5STdaNU1YcUhBOTJDdVoxWngrWUpUamczTXhTTzEyd2UrNmtiOGQxMm8xUXZ1ZjJvMlVZMHdKaUR6b2lYQS9oQTZVUFVMaWFnOXBiRlJDZmRPUTZEYmVDbjRVSXFyQzdhbTJoUG5jZlROTitEMGRhbEQvT3ljSVo2SjBTMlR1Nno5UmlGLy8vaitUb1pkVEZEaDlsbGV2UlNOTTNreXA2MTcyMGJDUTc1V3JyQjFSMjJXamNJNGZQUldSaTFvM3l5dUJVNU00SnpJQnp2YXo0cTRjb29zZk5TVjVGTUpIOUg1aXNaakZ0dUZxb3NSM0RyOEllNXA2WDZIRE9Qc3NHZEhpeHhVSDNoeWFGMWNNZFl2ak9ES2FkdjNnNkdpeVBybDMxblpwVGJ6S1ZvWUFrdS9palAvSmlnRkREeFU4TjY5VUZNVmNSeCt0OVkrd24vV3Z1YWJ1ckQ3VHhucjVnTFZjVVk4cmo3d2JLYS9zT3h0cG9tSUlZZEZjb1daeVpZZlMzNHVzUzkwK2g1Y0M0OWhIUzVUOHRkdWRwL05VNHlLZ0QrbitOWER4MmhmL1JiOHh3OC9NdVdvZDMyMEc0M0o5Q0MzSVZBS3U3L016Ni96VTFCaHJXKytkRk9RaWdnMXIxcmFpVktJb2xIdW5sVDNpeitDR1R0clowZnlwdTM5dTBWM3Q3bFBkTHlOUGdoaGxIZVFSVFRQeXFKcmVmcmtOZ2hUS0luZnVrYUMxRGpUZHhldFZ3dllIV1dHaFdCNUh3UlpkNVFGbUlMUTVaOG9LS1hydFRySE9Ra0tjSk1CTG8ycVNVaVg0L1g3czlSMStvSnAzMlEzR2RXbC9qaWlSbU5JUmZkWFppR2k3TFFDZ3ZpMzA1RTcvTW5TdFVBZUF1UVZwaVpWSFRlNGRCYmNUY0NSNWVpZlVmOGZ4QnBCMElnYz0=",
"pin": "111111"
},
{
"pubkey": "021391d86095d6cd08e5305e03b236a962998c651bbf7723d8b3b57d9e89da4c7e",
"routeHint": "030841d1519f19c68e80efc5ef5af3460ca4bfa17486fda9baca878b9ef255358f:2199023386625",
"alias": "bob",
"pubkey": "02a38857848aca6b32ebcc3c85d07ee41354988f4f1e0b4e6ccd255eee6ed75b8d",
"ip": "http://bob.sphinx:3002",
"external_ip": "http://localhost:3002",
"authToken": "tMGOUuFT1/W11kP7a6rB",
"transportToken": "MIIBCgKCAQEA0xtWDI1jz6B2XuRvm5fCENfLYfGjFhXyTAibm+vnyYUP+7XOhVtP\nNze7lXRjifSfNarJ20BgizPHQN2HpFGAHS23tJWYS7JRlUVMdejDaxy3JjT+56gE\nezQ4aVhKkdEuEHjVWzQNIMTI3G5wXogtx/e2C69HIzUO7fnR1bn0ZFTFB3hX9JJl\nwysZPxxryVBu+PNp8aGRYw4aHX6pQKvMhtOXBytDxkSJFOdLwfQzN6Nvl00zsq5o\nFoh0ZdIBLtWSJ4CQbqWh9aukbLxws/rF+i7VyGeEIswQh+9RQy4MEgNS+IoMyDC0\nUdctzzAaHUvsXFFRTrXaC6qwzITGr9x6IQIDAQAB",
"contact_key": "MIIBCgKCAQEAwuhDmk5+S3DKCsIPJn+679WSkbvg13h+XXePK/O7GdvZkAwelH/7QsJ3WP3cIXcJ8f8aQkUNx56l0ILjULEeE28EdOGCzi2Ld0ME3i+7WoSkyb+lElvV6hiiTvOKkGLcEbuvFgadnHR++m2IdTMA1IHZhGCHs3CbCbfCvC4kpSrOCMMGrnkWyay5d7Gf8FOXHwCDGQ1akyO6gQFvR2so8vtVOkcMtF4dnv3dg+eOM/W0+nFbS+mPS1fS0SYWtLKIdK68iDaB2B47yAXXJfLC5wyvnBv1aAhi/PyPLqFPTvrEHOVeolRmh4J1JjvJDjS6DJMCTWzjfVcP3vUiX1VYNQIDAQAB",
"privkey": "MIIEowIBAAKCAQEAwuhDmk5+S3DKCsIPJn+679WSkbvg13h+XXePK/O7GdvZkAwelH/7QsJ3WP3cIXcJ8f8aQkUNx56l0ILjULEeE28EdOGCzi2Ld0ME3i+7WoSkyb+lElvV6hiiTvOKkGLcEbuvFgadnHR++m2IdTMA1IHZhGCHs3CbCbfCvC4kpSrOCMMGrnkWyay5d7Gf8FOXHwCDGQ1akyO6gQFvR2so8vtVOkcMtF4dnv3dg+eOM/W0+nFbS+mPS1fS0SYWtLKIdK68iDaB2B47yAXXJfLC5wyvnBv1aAhi/PyPLqFPTvrEHOVeolRmh4J1JjvJDjS6DJMCTWzjfVcP3vUiX1VYNQIDAQABAoIBAQC0MF4vTdncjM183KN9CCEekOgL6xGWokLQzjOCgrW61lFwpoOu7hKwSXBkyWy1U4PSQfFYytZOchEBj7/vXY9ckAoitEllqx2AiGj7sE0ZBgACtDY7nsNIxLVpICY+Dec+TbE0P7F+bwTlKFY7Y4ek7tbVVxidf8EVXtmdd1tRhX+aevJAyeGtpSWEO2Gkjinyn4alvkax2/gk4curmPfuMBnYd8vq8i+k5WW0RQDJiBHx5QQg1hz0fSTFipaFqEhuRH5RmsbIbazwQP5r8Rd1Tvx4NTicasywTv5NSsV6qdmNAeIv3IDNrroqJa2JsaSOfHljfq5KewSQyuZSJBmBAoGBAOs75fnLZaZxdMnrvf5yk0RatRrYD420jzJW6X5J20TUCGNo0PibLs97mRaIajmrGfT2qIWCSPoOViRnXHLfSmb11A4msVBvxfYO3dxBBs07wKhPulMkGaqe1q+/gAb3ZS5XSnIPBEXGnaUdwUwEU1FFwjatJm3S+lQ+nzXGDlr5AoGBANQdA6qGK50iZMcYwBvJkfQEKEgRpc/GnsP06id05ci+qeXvMzu4P5qRkS6lc6zdmLkGvyAX+JQ/PtuUD1KbMA+wHek4sxyJxeumRQE2FSITLWV1GxGNQG6ZN+l9L+g8nPP3WOl9+Pdr1Tavsq+KotUG97O+uwkSR/uDVfHiZdodAoGAGUtEjFqhoIccnsW5lU2upi/2v18yNPOQXkJYMxsv97Ow/zd7GPBe1TKeIH0kpvTOArgvIMQEota9zoZKu5NlBbMzTR49/L84EyBAHPnlCFZ/fdms2FnOZLlVrmoyEw2xFI2QVLlmpTYZJ3MOoOTqLJgKrSRrOG3yOvLM3dRhIMkCgYAE2SzuRubUTqbzDhPGDtNxOm8ZRp39o9KZNA3uHPPrpMAJa3BGWy3JAK7K3ClKuD33bLoNp76c1N1A859uCfINSb9FR3CApH2Lp19Iac4N21ZcTVLzEcF5RbNLePsRWeFUikDUBXcdYK+c8mMpNAgIyoH6788io/JVQ2lBgCVH2QKBgB7ulYlK5rA1XKhVir2mUZxv+tJTHMx1gJor4L4+tGfftAP11PGBIx9PdivnmY2tG03N+kFwo+HGc6IOs3eFLhSaV5KFiaqUhpxiZH/7CzzNTYIxtU+IK18XPuBDtHLuTAVOseV+WghJlCA5GdzJpfNqDHQGJuHVJ6TCLaDpPwMj",
"exported_keys": "a2V5czo6QXdGUDYwQXdubzZkUERpUkNZakJpSVJiSSt3dUdwcU12V1BsNGdtNjRoYThTVzBTdk5oWitURTlCK1ZrSFlyQ21XV21hTHNKclpsV1hESDZuV095cXd3VFNuZDlnbzJxd2s2MCt4WHBKR0orMHF2N0U5QUpXOWhmdE85aytJa28wUmcwT3VIMHVISTgzc3MydmZyTDFwUGJ2RUNFSkNuZW50Ty9xTzlCazZoTzcvbHFERTluTUtyK3BTSk5vbENNWk1FQXNIbnRmcFBUVm53Tk1XZ05oNW85OXJmcFluRVI3UGJhZDJqLzMrWkpzMWMrVmtQR0dlTHQreVdqVWZuaUc3RFlpblRkelRsQ1puSmxWd2JPNDhzaHZkYTZDRjBiNTlqdWhiSCtYY1pHVXN3TDIybUZ4bWpmM0dWZ2FQbFp1dUdVcllJSENsZk9XWDdDL1BudlBiOXBvZjJLT2hPWjh6bEFTN3BTYlBMMWIrS3JtN3pkZTNpNFo0eUduNXE2TDF4eFVOSC85Ui9vSlBBMy9lbEMybnhyRG0rSFpleWUwUE9WdncwZDN5K1ZaclVTY2FBWmVMMkN5VnhZaHpYWkUzeFY5TVFBd3pyNktVK3hlVmtpblcyNjdWMU5WbHpDSGFHd0xmakZ5R2ZMY1gzOW1zVnhwTGs4aUtXb1YyZmVMeVZWb29ja3pvcDA1b2RJQ3ZVZFpOZHpkalNxdkZlNjUxSjZ4R0w2OStHWnZYSXhIVzhlS205aGNhOWVEUTVQYXhBRys0aDJTTEtRTEhhcEwxbm43Q0F4VmFMek9YZmdwLzdaUGx0RTBYZzZ3VHdjR3NJTm5JdnlyUGJpR3Jsa2RvWG5LT280K2tUL2xHRFhKci8zS0lKMmJFOGNadzNSd2hCTWVRUTV2YXcvamR5d2g4RVFlUDE0NlQ3M0JOdmcrbi9JbHk5blZMV2RFUzFLSkZkOFMyamlYbzJiNWxNeDZJZ3hUUVlzYnpDWkFDbEdZTlJKWFdlU3o0OUcvamFWVmd3RVlrRTBUNEwwT2RiZHlvRU1uYUZtejVSQTJjUGh6Mk15Sk1hWHVuaEI3cEpwZ2NBWjJzWTVJd0dLa3BNRnFsSCtBdzNxRWJKdm1lL0pPeE5vTGwrWUd5YTBxVnMrZ1k2OU9RVzQzMXg4RU82SlVKTDRnOEJQMzZnVEh2aGhTNXdKSW9lRCtsV2dSRGNrYjdxUE5aTHlyL2IzNlU3RFpKL2NQUlFxYXJKL3AvbXV1Tk9TdTRESkJIbklJYlBEVmhkazk0SDVCTDk5L09ZcTROUHJOdW9iOERNUUxZZnM3bVlkNW9HYzVjNXpxemJlKzdidmpwMWtDK0RBck1HTDRHVmQ0LzdWRGNPcXM3dEtRSWg2WkllNHRxdVhRNkhiWnQ5VTlkUUZGYnROVVVMcUVYcWd1OXlrclFta1Ztd2FGNlVJMCtSS21acDR1QldDWlBlTEF5QnFUUlBFQ1NjV3hSZDlUQUZjNHpOTytUbStlZFpTVHU4NUMzWFcxUHRzeExwY1pKanlmc0VEWnh2ZTI2MURTOFY5U3JmYTJtTmpuNnFnSXY2NkFOb25BdWlZOFpSemxlcGxyVzdNeDJrZkJhZHpoVHp3dFpOL0RhZFZJb3k5VEhuNEwzVlJvQ0RMZFVHNjRPNTZNQ3hybEJPMUt5RDNGOXpSMWFCRTZEMXN2K2F4Q3JvbUNLd0t6SVJ2L1RMOFo2RHo2eGV6KzBWbnNtTWJIRGVaZVU3c3NqTWNORmw0dWczREdXUnVoZUhOc1E2a0d2c3RPWTNPTC91R1BiZ3ZUcWxacldjSDhHcmlzUEp1ZVAvZjNZMHUxeTJPK09IZFIzN0lqeFVyMERrNENNMElMUjJXc1dEZ09YS08zcTNJRU5xUm5xS0lGRDJGMUhJeUIyWHZ1OVFwUGFjTHNTdTRzMEREVCtobnZwdDI5SEZlR1hPRmpmczZjUTUxZ2MwODJSRlFGSDEwa2NhampZN0VRQ3VJeTI5ZWxRWkNiRS9KRHQyc2kzY1k0b1BwekZMOEdHWm5iZm5KaFlQM2NQMWgzKzk5VlV1Mm9aWXgyVU1uUldFcEdHTmQ2c3lpWUs3MXBLM1FKV3lmOXNVR0M1MHo4ZHJOc1d3akRDZUdGeCszRmdYSDZwa1ZVVEhzMVBjOVJvdklyTnozSXdEREM2STQxRUg5dzdKZWdCQkNKN3J6RWFtaWxKYlRyTU9UVnBremZFbTN4SHI3NU52SHZlWXVKd20rdkJpZkFIcE51aEFSdXRWMVcwZFpsb3JwNThjcDFGMEJNbHlpY1FJa3ZlNFpqS2RqeTZnUUtpMFpRejdRdnlzVnZNWjdtODdvajVrWUtFeE1kK3M5WERqR1pCVlpLRmJqTWpqaXQ0MlcxUXBPQTllZ3RUZnFUWUJpM2JkMjNEYyt0SnBHUUhCWHpESklEWWZOOXpJa3Bwc3FTTEZDV0p3bTZ6SnBuQkNvZXVqNXdIWG1nWmZjM2taR0xYNFlza210L252RDE3Rlk3QXE1RDQ0b21YZ2ZZMzVWY2dsTkg1N0U4SjlBaitFbXBoVGlTL3NSYmE1d0k4SkVaekFKdlRsR3NQUEJBNSs1VUlVNGc3bCtUeDZ0UFFLa2hOd2xON2xtUFFuc2JvbnBjWlkzeHcrM2ZuaGU0Sm1STzB6b3dLZU9yNFVVT04wcFVXQmNka0NBcE1ZUURWZlpXV2lsOGhraXE1QUF2THlnYUNiemlRNFlNMEt4aHdwaCsrSGYvWUdnejZ0dktFRkg3R0liOG5VY05zTXpHWUlDQkRjalBpUGxRdjN3Y1BBc0QvTkhPYnBhSkhLbE9TaXZiRjB3V3lDOEFVTFpzcElyZW0rcGc0MlNlZmFOYldaYVlBYWIvOHhnN2t1andmdFdjU1hjMGhYMnQwbGh4Z1ZpZjVMNk1xbWliUk9yOXNJRVNQMmRPKy9kME9RSndLckZ1aDB1S1NRUm1ONzZTLzhkN0ZZRW9VSTlUWUZPUzQ2R05mQVIvdjVCQmJCazI1Tkk4MHltQ3ptNEE1enFzTnpaSGJRSURlYmIwOVowd1Rrc1RYUHhTNHNLK2prcmlyeVErSnltajNXZ3QrUzZoRjJtOVlYYTJiUWZFL2ZSNkEyTnhRVk81OHZtTFdaVFpIQzN3RWhNWEdVeTljUm1yT3hRZUFlaGI0cUdmVU8yRzdBRk5lT3l5VVhrT1Job294VFA4TGk3SDQxSkgvRnNld1ppV1hhd0RORFBDNmxUdUUwT3kzeFlzU1J6SXk2L0Z1MWNRMU5RakJyck1sRE4vMldBTjd2VXovcWdyaDRLVTFWQXlldk5vUkZGbFBaRkVWRm5SbG1XeTFEWmpQRlNFMGtaM2E5anc3ak84SHFZTXNGU3l3YVBQNEN1RUNwS2xsemRraGYrUm42ZlJLWC94a3pXZTFNb2RUeE8xQTErMUdpOUt6MnJtTUpaak5DRE9nU0FMYUx5T29hbkIvWWJBZlhFeTVvSDdYc3Z1REVJSlFBTytHVDNmNE9OblRHbk1oU2ZYNGU1VTRiUm81OWIvWWo0OFpZKzNZdWh4dDMrL2V3cUcrcWx5ZUg3dkZrQ05Bd0FIazFSaXBUd0Vic3FJTlJpd05sa0NpeVJXMkV4SjdUWUhCTT0=",
"pin": "111111"
},
{
"alias": "carol",
"pubkey": "0364c05cbcbb9612036cc66297445a88bcfc21941fd816e17a56b54b0b52ff02b9",
"ip": "http://carol.sphinx:3003",
"external_ip": "http://localhost:3003",
"authToken": "f70soe/8GbmLjzLlyMHN",
"transportToken": "MIIBCgKCAQEA0tntxUY9hUMSmW1ZL5l1V9btss56bCrqFfWV9+9gaNxKBuW+2LSw\nJKvhKeL7IOfSqK9Lq4w4XsBC1sEDA30W48yDzf/khEKX6gaHQcpHm0hnPViranGu\nUNDOXLk7QnVYN/rSwhOmVowFY570cqB4SBXaIrLX31ytKk6Ni3c/sseM80QuC3lq\nb+rbfTu2fygp3P3ro71WzrWYlw8iob61UWbXXvNqqIT4yEG5RKRqZCqj1VFh9JlE\nCjGfUDqSw1UBdY3sd9QMsHYI2vfn91e3/TdI8rO+8IsYxpCcDt23Y8miwbGlCo/B\n3RJEsPFwJPxBvvvtU9/pU9QoMROIX3qgawIDAQAB",
"contact_key": "MIIBCgKCAQEAmVl0urwfeZLhIQ1sTeIeXGWUCUvCvmN9z6gLnjqYVFmkc2lgwV3VKn8/RainrfWA0VRp0u1OmfcAsqW3i7srB8vtv0S+CXGk8vtJfBl52f2lnpKWUCXq7Z3eFWZi86GL+GHKxWAx+m98qf588/g+UR/VU8w67lcaUEK28f0GqAGsORP+CpnzK0p7gZDkjzBoi/H8LceLC8iv72K8aF0MszeQgsX8dNx6VjPrTnDkAX6ikxcuyeKJ64rPz+RENlrZE7At7Q070fGOVgO7ARHUPK3AxiKDqiHyhBXYbFEFPoKSOPZr9xm8UffQtOi76dwfAhFcp/z/aG8mcP+mle3tQwIDAQAB",
"privkey": "MIIEpAIBAAKCAQEAmVl0urwfeZLhIQ1sTeIeXGWUCUvCvmN9z6gLnjqYVFmkc2lgwV3VKn8/RainrfWA0VRp0u1OmfcAsqW3i7srB8vtv0S+CXGk8vtJfBl52f2lnpKWUCXq7Z3eFWZi86GL+GHKxWAx+m98qf588/g+UR/VU8w67lcaUEK28f0GqAGsORP+CpnzK0p7gZDkjzBoi/H8LceLC8iv72K8aF0MszeQgsX8dNx6VjPrTnDkAX6ikxcuyeKJ64rPz+RENlrZE7At7Q070fGOVgO7ARHUPK3AxiKDqiHyhBXYbFEFPoKSOPZr9xm8UffQtOi76dwfAhFcp/z/aG8mcP+mle3tQwIDAQABAoIBADLlthCkj+3SClbmFaRkAJ+6N0A+nQyECSX7KKAD4rtcZXDI8Qw9EJtiUKXWLJFYgsD3u4f+q6/+g4TH6/u8y7NyxB5PuqN3zL+5F9LQwdjQjz/qd2lyrF7hnuyLZxxl6gcurhaErxHoHwBtLxvqsQRMBIojpwukbV9mRUJcMPFh2TgMZ30t0UpCRPpWaVQocmAAelbtmtGAxMK/8BOq4vS0EquxFXPXBYjSB7oCAU1PcPsjHNAdGykLl+BBymw7WD+7mmJN/nlXiL207HykMhSCKBUJwJnjwYR3N0iD54Wgy5i2k7Iqb25vo3wjjLbi86X869P2DZ2Ta9vWGJ6WeAECgYEAx8EoxuwjvrYy5BgxtJXIK8HGio8w7rAjABr8wMonE8BJONa4rxVEKCmZAGn3pJimuDDuhyS1jxY0XXox7/UEN5zLBUSYohfuGylH0iMulK0oZghXz/hRR9tqCHTLGTDeU9WadBwHweEwECh/csDRAwDdRw/McqETiz0Iy5rK6IECgYEAxIdLKXLCfHukE1sdbQx/yvRQ+6dYWwbeMtklFCY52VGQwzJc8QvXSu0m0kVuGUkzEzcVQpT1fFCA5gCoUUQAPYhctRBNDCEiNpK6eLaGJZD6PM94iOgW9VGqczrmDRUrhq3m+qvsBCDDBZyd6Ceikg+CBWPRoDm9mhT3Fd19U8MCgYAP7oT9EJptPITkklVsjMGxU7wtEuyZLO0ttflQuw7Q0XZFlUKXnD+aYG72jH0W4KHzcNulZbUhW2kDx5oyBD243cWHfwgZbYUtH2a+CNZPP1xIfwPZ73k0HPjhAcetE6u3zgKKni20NeyqbUB0+5HwBmKfp0/sGJLBeTW5X3gtgQKBgQCIlWqUPNCTyS4n0ZwqzJQIDjI2I4CRir1kY2uUjFiKA1jzgA397HfM9/KSEnTJGAlqIk8hPfs6UYyzzOMtz2/HU/zyTYjulBx+Bw2XlWq3swFmv94KcBp8liw690Uo9HySlkvADTnzSH2hac6IqPsgPazkaBIpI9f0vPtX894FFwKBgQC5crdUYkekzRHUnotC09V3BGBswcEdQ9YNsi+I9JrHm5NGaK84miaHV8vK4IL7b8YqJmU6Se40fpmo/3mQ8KRc/3+ievDUrzVqH4WdBC1qWpv1Kro/PtqyhQLAGmNr4yuo5Ptsc5ISbAJ7KiO5luVymp2GyF1ILfU+/pdyGWQKjQ==",
"exported_keys": "a2V5czo6QXdFMTNZazFxdXFmTnk4eTcwMlFreWxhZ2xseDIvKzJQV0U4N1I1Undva0JJdlJCMjQ3akxwWWczb2cyYXlYSXZneWtIYUdmWEpLNUpuT3dxNTFJdVh4dDVUUTFrNXIwdVVPMVpKTEtvcUJZcW14VisvUVdKSzRLVE5razdNUVVscW9DYVcvRkloS09ocnJaT1k5ZUx1eHRnR3kwN2RpcjFSY1NIN2YvanViMmFoZzBqUjFrUCt1bXVncUZXNVA4V3VSNUU3NnFlQ1ErLytPU3h0UkJvYmdVc3N3eHU2MWZPd0ZHd1RrWFpVTU9iRHlnL3VQbFdNVjR5YVdYeko5L0lmV2M0OHFxRk11QnQwS1NWZTZacmJadWxleS8wWjJoRXA1c2lldm44V01idG9wdTRpSjNTcDlMUFUyR2pZdk1uc1dFV2pra2dvaG1PWUJKSHJ5Wm5WR3pBR3I0bzJpc3dacERNWmJ6THp0R0J5Rmx4bW9oTndqWUYzOUxkTE5SYVpicStnK1ByV0tTL3RuZy9SVitQb3Zka1gwbC92NTRBaHFwUElid29ldXhoU3VjY2hNVkh3dFM3QllsdUVaMmp5N0k1NkdFcGdaV1I0WTdBOE5VQzJkc0UwWHF6QkJGSGxIOGMrNUl3S1lMeVlPVkQ4NlFza25TK01sbUR1c2xHdjZubVJNdWErMU9wK2kzcWdiWTZqOFMwQW1GNUs2OG9heVhYK3RSUUxzbFEyM0pSSjdXMWNWMGdCbGdvRFVKLy8vaDkvV1BzYWlXdVRMM0FRbkUvMHZVaFRGWXY0NS9abXR2S29SNjN2RUdVS0VmSVJoSFBHM0ZqNEdqelB2WWZYWktMdmFnbTZVL3l2NUVqMlhQdGRrK3pBeVAyTnM4MGVueHdxYS9mNzdMeGdIZUdNcXdIazdmcVJrcjQ0KzMxdDgvRUp5ZlFuUm53QzBycS9nejRab1d6R3E5RlVacmFsVkdGaDU0UStIZCt2RHlDOTMyM3V1VFRXZ2JtYTF2ODdVS3NOSGY3TndUK1Nhbk5FV0ZacVM2OEFhVS9qSlVRUnkwbUVYbWMzamplRnpxRUFaa2lLYitacmNFUGp4bUY5YjR0Y1BRV08rMUpyMWR4WGt6NkdJYzBhUER3bVJKdXhUNHlKb3Y4RGpTSmg5RUt2RDNXdGNVWkM1L0JhOEp2eFpHT1RYY0g2WElBdkFnanFUampCN0VibFJtemZPTE1qbG84WjhGOHhSd1hxdDNQRmVYdk9ITWpvcjNzU1JQZW5OUlRlOXI5VFdDTGhIZkdxTXdXaXB3WUthMXBVMDlNZGlYaDMwaVVvM3N1MEFFdXlrdHFxajZCcDY3cUtvUmFEcjE3dktFMjFsQkdmQWwzeU1KbkYvQVJWQkVhajhRYk9yUnUzMDF1bzAyUDdWclNGWjlYT3pmS1YzNjVEUHdqV0Y0ak02ZHNkK3l0cE5VTnhRcTlwTEkxcDhERFhpSTU1ZUFwdDhmeXQ4TlF3ZnJ2L0hPNnBOOEQ4aitncGxxajNPWGlsU0g4WlVJN3ora1BrbWFVU1lVTHRUdzI5L29LSWJRVU9QdVNWeUdkTUVCZ2pMYkU2R1BUZUk3T0ZMdkJCN2JBVzlQdExmNjlwNUNCZndUc0orcDAzdzgxVU9hell2TWUzUG5hK0ZBZnFtRWNzTmRpNzMya0p4cXBjTVIrcmhBLzREa01NUTVORWJxY0h0eDU4RDh2Wk54ZmdvSVRwUzVlUjBGVFl1czFGK3pMSmxkN2NhcjByUHdQNDZ2VVVBeEVyQmVtdnpiVTArb2pGSUl3QVFZQlNJZFNjdnMwaWh2ZXVhS2xTcGIrM3JGc0xLNkR5TWtwNTRyUjVlNXYxbjVjSkZuNlBBTUNTYkd3Y0o0RkRkNTFDV3hnQ3VyVEd5T0JBUEFFcUh3dmFPazNuNHNoTUNJcUhYTmpyMHFVZTBwRDZhYkVKc2VXaGtCUDJLYXIzeS9kZHlQMjloSkFLbkNaUEdnT0F1K3VGQS9pWURpMEtyNWdma3d1YWpoUFkrVFFOOWNieFJpQ2lRZEhSZm5XQmRGdGpEM3k4L1J3ZXlHeUNFKzdweWcybUprQlRobUVZbENpMy9PaUlvV2RML0d6bVhKNEM1NEUxS0lzaWpwWU0vNkJPVjR2bFA3RlVzSTFZcGN1TXdLSDBrbStqSndhRXFxNEkxeTVEQjB4aUVCRndYY3N1L3l6TkhwL1NvY0pDNjdhZmpya0J1ZVByMjZRNnlhL0xQRDBBclBoMnRyakJ5VkN3VWRUREI1bHJ5WkRYY1c2SEV1eHJoU3FXdTh2Q2RDMHpQbWlYYWExdzdMUjM3bTlVa0hvcUJyY1FpT2NMMHBwLzFjREV2MmdWcXhuM0FDQk5WOWdlbExZQm9pK2lkUzFTQmZndC9jSjFTYnRXM2JzRmY1aGdhT3BKQ25FUU5RUG5LUnoxQTUrRWRTM3h5OFN1VnJtOElRKzVtL2tpMkorRU5sL0hJWm5ENjh1RVJoOWVrNVhoV0hkWmZHZnNCRXp2b3hDWTJTUXNNL3NZeGM4eEx1VUwzTlgvUWxnWVFJVVpJRFp3RklpZWtYOTZmaUtsYjVaQ3p3YlNrczBNMHFXZ0o0WUsrZGNleWk2anMvTGZTREhFbllFQktMRWw3UlhjbkMvb0tjWW1IeG5mNlFZaW1IN2dkSW5mM2JDb2M1a055U2ZQTjRXVWZJc2xXZy9wcGJDbFFuZXdrYWdCR2pYOXJpSSs4a0YrbGw4RkhVVTdKS1c2WllscVJyYzdud0QydVZwc21icU9HN0RxTzdvRXZrbHEzamRqOVJSSkNEQWgxM3N3YjcyT2JrcndLUEtaK2xCYWtObnMwMkQzOTM5d1dRV0Z1QWhGTTBBOEJDd2Y3YTBoaEkvOGN6d0FON0FkaG14Nlh2S2d3cWhsdXgrditLdEtmbTNkWUVHbFhESHJ4dFpZTlRack5qUVlRRGVjc29CdmRsbXN4QjZjcXBuWEdZZldlOU16WW13cld2cG1UN3VnQkJmNCtxZVIvbjgrVFFSMjAwUEVPUnhVMkZRY0Y2eWpoY0k4c1piVHZ1TW5aY2dBa0dwY3FqZklXbDE4T1c0dmMwdmNra1JiWWN1YUZhNHJ2K0tZWXMzMXh5ZXlNT3JpdFJNQTkzcEJXTzI2Wk54YllLK1UxQWdaUWMrbWRkOVhrT051QVdjdG5WOG4xR1YySnBoRXAyS0QyL2V3VkJvR3FQVm1XQkE2UE8zQWJab25ISHZiNkNZS0FRbnF4ZXhlQnd3QXZ6QjhpVE9GQndDSDJPZERHWjIreDYvZVZ6c1dXbWNwNCtrNHViRXN5VHVyQnZwYnJvSmlSdDRJN3dBcDQzT3FVZXR2UERWN09zN3JQV3NOcEs2bndISE1ObFk2akIrWTlVdytGS0txeUd1eC9aK0FXYnRlZVhuc2tmVGU1cXZSNGhIMlZxS2pDNmZvL2p5STBCSTNCdytodzRYNktxdDhZN2pCeEV4dzVJMG9keUlRaDh4VnJPa1RNZDVUcHR6bXRDR0QrYnBlYUtUSkZLWWhyRkh4MlNNV0cvcWQyODFVUFBEZSsxQmUvcWtNZCttUi8xYzJQTkdtRnZERVNiVGJrM0JSOEdUcERRNTI5ck1sdz0=",
"pin": "111111"
},
{
"alias": "dave",
"pubkey": "037ec785c6004d512ebaeb0020f81a2bcdb6fccc9539f7b891f704289ebc65a4e3",
"ip": "http://host.docker.internal:3004",
"external_ip": "http://localhost:3004",
"proxy_ip": "http://proxy.sphinx:5050",
"admin_token": "r46bnf8ibrhbb424heba",
"authToken": "/jbGaLG/jViZeG5dPq+f",
"transportToken": "MIIBCgKCAQEAv85pKAmP8RC1LKq1FG8acSLhCaot+dSEbqPQxCsWJNdzyIeg1D4f\nwH6DSD/+x/ARlKVF+eLwUpVWqVFo+GbpCXkI6emnYwPDwvqkEMu2i8NX4HlzQ9ZD\nDsZzuYafZLBSeHQtOdqBzNEIVHI9tic5QjaKGFGSWjNegObh+vdRJJhDcT/lEZUe\nrOKPHzXVZfTGqWiNoUOZh1jOuJC2khJYsjGjtWutp0kbnB7hc9r0oCtnQ/ebu3sF\nUi61GxPJtrW9Ihw/jfnJN3DBV6NukLh40FAfN+0RbzAtsG665gWtxAzK8+FjL4rq\nG8tJg4cggC1rWS7hxSddc5XjANc6kfBvYwIDAQAB",
"contact_key": "MIIBCgKCAQEAqRulW+eZIOXQ6XzrSk3prC/n5NwemKYozC3D+QJteab7UDXkhTZ2wXo6ZHAOaSD0ONCYAgwk76VPQUPW7v2F9NNFPnxHAzTsG7SuM7wpPH3g7qK2oyE5VsD3og1aJBwmfH1bOVxlrhnHc+lBiYcW9v5bC3XJMVaZntmITC9ium5+ThOXaerDgQHk54kdUSH6SxkC87kZj36WqU2pId9lioLLVgtqAufZjeOpX5GbBLzFYN/SKhslGbXH6z/PPczHsIUedeSQX8yJ2Hh3ROShbfK+7YTYdvFWSMdJVSwXmHfMveovqbwDzrGrPAO91//06259LjU2TkiH78FWXlcGfQIDAQAB",
"privkey": "MIIEpAIBAAKCAQEAqRulW+eZIOXQ6XzrSk3prC/n5NwemKYozC3D+QJteab7UDXkhTZ2wXo6ZHAOaSD0ONCYAgwk76VPQUPW7v2F9NNFPnxHAzTsG7SuM7wpPH3g7qK2oyE5VsD3og1aJBwmfH1bOVxlrhnHc+lBiYcW9v5bC3XJMVaZntmITC9ium5+ThOXaerDgQHk54kdUSH6SxkC87kZj36WqU2pId9lioLLVgtqAufZjeOpX5GbBLzFYN/SKhslGbXH6z/PPczHsIUedeSQX8yJ2Hh3ROShbfK+7YTYdvFWSMdJVSwXmHfMveovqbwDzrGrPAO91//06259LjU2TkiH78FWXlcGfQIDAQABAoIBAHqdiA2WZOp8mDjkEbrDuX3XEn5XuHuYZxZ8zI7d2sENeUWUfgi1D/CDjplKwrgpY8taPA2n/pQgudGpvct12c5F7fw7okXJ9rS0EmeCtCefYhvFsUWhDnE/444FvmlWW/WB80YpH7TYDk2WQKXWZKlcjmlF00bJ8wNB2VjcNurTiu47c3CODlKXPtM04tiqEyGvjbvqBGABOC+sj9rXOgoYuZs+BqBZV4p7IfEDixZke6ltuEH8gXotHfl9RoG0Moz/J6gipadiqz5GDlu9XUKfIbsdSiko30nwdU7AV0VFAjel12Dzl08peNja44yoMKUL/9NaoN7HmB8a9naivGUCgYEA20JGkNVQQMh/wV9Q306UQ+rqgH7FFaqkfH7W9h6t34/GjTZONO1SpyhHLJ84rut1+P1vuZPOKbeJEPSo2tglICaBp8yJNWDpKAvmqvhBjSss1a1d5Yaz6DmVQOaAcfH1KJbpZdHvCU83v8nmUJJwKfrf6RbgOeZXuaL0SE4nphsCgYEAxXIBzTi/QhirP0ed1KLt2EYlfo3NA81gT2CCtyy5TlUDC17HMNZK8ay0P52CpYDvr2ZVje4M9kMJxC+TS/URIaLiCt7Z7oARqT2ayTwuJbtjPZDyFk3Dfa2fJtkVLHsf7qDlb9fyQeGaIANx1qvy91y7GDaWNYJn8msPpP8bL0cCgYEAh/Q/hz0Nxy3Lsd7laaHy4249vDFfCYFG/v8zUWdSjwY6qoMa2Uyy7H1YLL4JysSr4Rlc9qhEtK9eaUobjZ9q3dWinaaBCb0utasze532H4++/DvEtjbhRUS3XIfQ61aJmoKA9KbI3m/ldKG/kwRKUm2B+6k4ng5LJQt7B36WrTMCgYBKpXyK4t5kFcGAbgn8nxB+yJ5aRy/wNRApUlp4+B6iv78j6FQ0YX/5+Io41srS2XlEfdLwksQxwkyJ8Famy+MLLXJ6G6CW67JBornHRMpJl5vAZfEwf3veIurdnArGQ1JiPFAhxamgQLOtUMAUIfP8kwFk+RY26rNz0ggbIBtd9wKBgQCh91puxVxze5c03kl8K47RTt7dtpEZGFSn2fSwwd4tuG2uU+ytozNkAKqIDBeA7TmiXVy6GA5M2+LGnSc1fhLOGyCa+OLwsxpt6LtPjCsyGAIHO9NLEhi4wQXgFhFxQz2yE3qDAxUf3vNzraAkcnqAc/t5lgTwur/Nxo+RdY1uPA==",
"exported_keys": "a2V5czo6QXdISTJtZGVNd0JVUUlHL2ptMndWZEhaYWF4b1dBMEcvd3h1OE9NdUNoWmN1c3c2SWVJdGhYVnIvMi9Fc2ZmL2xHbktHMXZVRkh6WE0zSnF6QU1ZYjVNeEl5Zm5PbTNGUzlIZ1lPQW9FaEgvTFBQUEM3dVFDRFFpY2hxTjZGVXFFWjl6eWdaSWk2amxVNjNZYUR6M2hWNWVOWkVsb3MwYUhleWhheTZwVjZybzVSZlhIaWo3VUtWbVRodGRFNzhUS3YwR0U0SHlqenVwZjUzYUc2Q1dJWnZjRy9pMW9qMHBOdlpaL1RQSHdQaGVRV0JoaTE0UTZ5S1hxclo2QktuaVNYVVJEazFBcmdDbE9YY0RNSmd1Y2ZpSlJ3OE1NdTJyUllWRHgyT2hubm1Yd0RQRW1mMTZ2Ulc0cnQ1RGMyNS92d2dQbUEvU29BZGdyYXp0YXUwaFZlSXFMT3JXZ3lmRDRTMXhnenJ1NzVUTEs5VHRHeW5wZWZDVGE2RmlHakpjZEdiNDV5dEljZGllMEsvU0x4WVV5ai9NaEp6d21CdW1yTjBPMThHWDVBNHF5VTBDdFdicmNsZGswcmc0N1lENXJ1WDlQNEtGQTZIVWRGcjVOWUt5dGlNUHoraEVoQVM3WWlxeEdIdVJacm9Tc0FLTmN5NnpEYmtZQWdCTWg5dCtzSWh5WmdJSzgybEVSTzk3SGxPd0hZcmd5L05IR2N0UGNReHg1L2tnOEUrdFdwQ2xQSzY2S25CYTZBbEo1K2pIa2k4VUxYSndpTjJ5SWdOU3JHbDdxb2dtQkhaSjBjM0hzbmcwUHNwdkZVQU1RUlZ4cmlyVUlDY2pmbUVYTjZBeFFjVW9FaVJWV0FRTTVDZmp4eG4rc1o4WTdDdlhReHJqRzAzekRjZmlYVUdSMVJON3B6UzI3bHo0SFBoenNVeEloOWhpMnM4b0szOU5nMUlPSVQvV2xHaFROdlA3Z3U2dmQySGpzUkYwNWl3RlVVZVhFVEF3VmJ3cXdST25zTWYyclI2N0NWYk94WWVWWjNPNndhTUFpait0OE5zSDlQblNZSTJLWHUvUmtJdGoveWR5czJKc0p2b1ZLdmNMWmVoQVk4VjB5V2ZHRTlXNlA1d0JtV2JkZTlFWDJNeU1QVG5pdVFxemNTZ280NG5vdWNzaDd3bjFkL1dBVlhjckRtTXNkY0dTei9kRWJqQUlUYm4yemhncDQ1RHVoY2F6SVppN3ZYTFg1WWpvY1lxVTU5dlpkbzJIaEFjSWpqb1ZnVlpPZ055bUxuNFZ1eTZ1MW0wZHZCWVREdnIvY0dta001SFpHVFMzMEF0c2xSMUxTWWluWTNrVjBxWE5rM2lqWVBUR2FXczVTUVA0R01SR1lSZUMzVUY0Q0E5N2UzbXpzTnF1cHIydUZBd08welNjTmU2dlN0a29qNUVqa3R4RFIvazdJQTl3NWlReWt0OXp3TjM5WFhWeHFqK3FYMTUrYXJJZCt2YWIvYVhCVlJBb3BKRzB3L2o3KzVJVU9JV0hxaUYxTXFRNUVBek9LQy9MOGJQZkYwTzlrVUxqSDJIbVNlcnAzR0lWelQzdWNqeG9Rbzc0ZVJhV05UN2ZTNzIzU1RNaHppcm9pbVFJMFUwbm9mQTF3ZDQ3a2ZFQ3kyV1FsdS9CMHhJTFBFdU9sdEF2U3R6OFZ3OHBySXA3cXB4R04xT2F1dldNbURBTy80OGYwT2oxczRNTUJub0JDbXNYOTlMWkJVdWh6ZXZpTklkSjVDd2ZWR2luZWpCSDE0WDA1d0lXSU83aTk1SUFFaUUzMmNwRHpKanFmZmtTM0dDS05tNHNwTUJ1Ny9WQXNvTkVLSVJwNTZBcGI1RktOcW9rMHByS3JQRXlZY1BiZWlJQkZjVThNVDlQOXM0OWRvbUpEQ2gwTWxkZFhMSWt0Y3l1OVkxbmlvRlF5cUkzQkoxbWk0ckM3Y0NIOXR5NzE2ak5SNXhQZUwwYllmdWc5dTlkTGN1Y3ZsU0pGOE42QXN4andMU04xbVFoZDhLUjd0b0FDWWdveXJFdjIvQTc1aXJibmNrWHNzYUxkNjE4aEEzREJFTWhkK1hmUjdPS3BFT2djSUh0THlnWHJJRlpFak1SNXhEcmUwbzFzUDlSUnh4anNYY1pCNWpKSVUvQmNVb21veG9xT1g2TUNxTDNaVXFhN0N4eGZLaUNZeDZuQjB5QmdxSG9jR1pFYmFHYUdaeEtxZENTWkJRWEdsaUd6MmozR2JWd0ZVWmRabUNpZzhROHdnMlo5em1nTnhQM0dDNlVMR0JibmU5RVYwQzczY1VqaEdHU0NnUVcybkxUckttenRUc2tsV21XajcrWmhpOWcweXdQUjc2a1c4NTE3Yis4VDZSVkJOditPblZJbWhpQ001MmdFWDNUbjRCdXJ2NGsrM010WnFDWlNVeklSbkdaMUhVU3hwL2k5OWJBOVBZcG44MEtJUlRtU3dpaE53WC9CeVZrS20xVkFkdHNIbGZFc0J6cUlUdFF3UmdzOEdmQkdJZFJiN0cwanZTTTBQaVdzVTVUNjB4cDh6emtOZUN0N1djOTJQVUJBT2N1YUh1ZXRRazFRY002bkw2TjZDYkVPUkIvMFZlWVdIQU9mUFMzdmtWRExlRy9jbmp4UXhGaUd5R2NONnZuQ0JGNUp3Q3IwbDF2TlpCMXNEOWkrR2psK0VVaXZWTHFUWUlIV3M5UkVaQUZhZ1FuNExKRHRsZVRlWEg3clh6ZnpGS25xSXNBWWppZE9McFVna1hWeG1SRVI2bWZLOTBjOGk5emI3Q0ZKWkt2WGZ1b3dpWEYrQnBlK3ZnQzE2OFM0YTh3cDNQbStPZHhRN0loYXNKSE5WQkFEQ1ErdWJyZVZsWk4vTSt5cVUvQzNJQU1PbWt5R0tkSURkNEtqQzFFYXVOY3p5U2RCTkdyUjlLOTRYSWRHVUhmczFuT0VSbHd3RTZoRTBNMVFWY3RlOG52ck5RdkFFR2xqR1h2SU4vZlBKZzhKN014dnZtWnBONllPYmNSK1ZzcVdYUFpZcHBqQWRRUlFRZzU2d0ZkbEpCNkVGS3ZYV2oxRENTZmc5akhXRWdFSVRDaVlsUnMwdnZLbzdrMFcyekJzNHNFa3A1d0JtR0NjcHM2bzFLczZFdi84ZGhTbHBxL1RHd3JEQjg0RkFyM0lSNHE4QzJWQ2x3cFIrdmh3cllGWjdSdVBSRmkwSDRjVy9PMmZhdjBWTThGYUtObWpaNlhqd0NELzZ1bUhacGdIRElTV2NONDdSaGU5WFZwV1lRVklFZVI4aXlZKzhWT00vSitaSWJIT0NpS1NMdVd4K2R4ZU9uSCtlS2NCWVFDcExqL1dFY1hvMXBYby84TmV5VTZkdHBMYlVPUldFbjc5Rk5YM0VkZytsTkpnRVVqWEN0R0M4ckhGU1FrZUszclI2ODRQeWYvK0VqeWlmbGhuckRoTEpPM0tMa1hlQXY2WHRTSnJHdmtONFdVaWJ3b0JYSHUwZXR2djVjbkNjTDE5UG15THMrS2xVUmRuL2hMRm00U2tnTFFyUU1tRG9yUnYrWDZPeTFqbmdwYTFKS1oyZGpRSk9UWExhQmJHSkJKVXBaT29nY2p1b21vVUpiMEZGWHU4REpXQ1RSakVsSFk3ZGRzTEsvQmF0az0=",
"pin": "111111"
},
{
"pubkey": "027c95215f16745999d69cd473ea4b216debdbb5074e53107872ee48f950a5135e",
"routeHint": "037ec785c6004d512ebaeb0020f81a2bcdb6fccc9539f7b891f704289ebc65a4e3:2199023452161",
"alias": "virtualNode0",
"ip": "http://host.docker.internal:3004",
"external_ip": "http://localhost:3004",
"authToken": "EwNOdUycNff1EQz+/FJ6",
"transportToken": "MIIBCgKCAQEA4w+96GjXc/sz/vh6QqT2PqJo2Vqf+8jy+DpJi+zTYsOsOZVMOvFT\n49YQMPuKh4F34aim6QtrCG0P++i57rAJA/BU9i/9HiLeQw1Y0igMKD6+kPbGqhxi\nINQapiEhp0jxpsCOR2tkDPFTtREY+6OWrfKVZgCyHyYZbgmCWtOY12jjsV23q7pq\nT9wvloxuNOWDNLkp7jRyP0ax7rUVbUMye5PgEt9HUUOIjvcbbZSuFA6YDTXVXOPl\nEolbezj+Kviw2rUTkA1onsdhR2pjoB6TP+uyziAcvODk4H32wBmvbtqmH0oQHIF7\n75bHV4yqpfUnV7sZhVdo/iKfm0dIzEkKHQIDAQAB",
"contact_key": "MIIBCgKCAQEA0UNa0FhnmuFUqS8GEqZxSTf9uOlAJ873W41sVVyFcRuMpKfMgbGUgqNCliMBiVN5+ERwFwruY3THHwPJe4yY4rgk4/OcWuupHhfyUIJ6nmaCSn4j4Gwu90YHQfcfvnJkXgMromJ0Ajgl3cpZEELcLydsNXUzqmTbe/DbRk3qImnMoie/TERDKuyA5L09KjTj3bAu+ZoK0EQQdiJoBt6IWNX4i608Yb59Wy48Bt/rw64mooCDmPC4QxRfPIV4kS45mTiTBs15xYvKzKNZlVfwaJF/hhd6Cm2qdzgtb+9BWfZeoehv8TEGDqBuzKVToMT575CqTOYkEdIlInmvbcb3bQIDAQAB",
"privkey": "MIIEpAIBAAKCAQEA0UNa0FhnmuFUqS8GEqZxSTf9uOlAJ873W41sVVyFcRuMpKfMgbGUgqNCliMBiVN5+ERwFwruY3THHwPJe4yY4rgk4/OcWuupHhfyUIJ6nmaCSn4j4Gwu90YHQfcfvnJkXgMromJ0Ajgl3cpZEELcLydsNXUzqmTbe/DbRk3qImnMoie/TERDKuyA5L09KjTj3bAu+ZoK0EQQdiJoBt6IWNX4i608Yb59Wy48Bt/rw64mooCDmPC4QxRfPIV4kS45mTiTBs15xYvKzKNZlVfwaJF/hhd6Cm2qdzgtb+9BWfZeoehv8TEGDqBuzKVToMT575CqTOYkEdIlInmvbcb3bQIDAQABAoIBAQDCa/q+4bP4gOvgeBEDWOKd7Uhs+UEi+zZ0OBPzxw8vxDHKdSAbSzq4mShvRzzRMt56XFNsBTrw6nlqBmG2ySzuT7nuk9Kr4pFwpTz7sg5shr78qO96Pejw0n5BunEixzMa6YUrzJ8NxM7hnnNbGVNq+AygKjEDWctV/rQrQI6MwuM5NB2ZUsYD/0S0X1OCGVWqR9krj3BnwWiL8Jzg1w0WVZvvkM+tkIWEadFKaRv59cC90KWrO0fbNaQGlGZ0PvD8+aE9o8odM64e3a4eEuQE4+Bimo7HezwrUzWl4yIQQZ4h2Q1lyDrO/m/u1MQ7h8/X5sA86MexAYVktTHkqsbBAoGBAOs9r8mY0VhDImnwzpunmf63PlmMBk4gU9izGXPggZiqasNtYZ09pNYuu2DP4lxK5kNpjn214R7duSVPsJ9JJZi7M5pvRPUYQDcxIqsNusQiIsTfFUhA6l2oPUdpt2QPn3G1PrGiufoW5hMOohYUs7A6SfwU6J0WTKaRTwTXumxdAoGBAOO6zc9Gfsfp1OAIXG7KgkZ6km2lRih7eht6QsXjIqsNPtZuUo26qG3PODGmypw4GykfN5uGd+ArlhDCWlZhN1rTtSvSMUqMHXymNkgAwjnGurjTXn/2jNDlGQGTO9ieITvo+IlXLIFEywZZrkhL5WFN41oHEGGgp9rk49qSOoZRAoGARxtUYZnB3e4dHuzdZwuYbvgw7px243K+JYitrus0AVOyBfSwRvl1NBDYLwFnqQIy7DmiCrnJnKzk5DRcbSmNJcegZ5Quwe9cqdI+anox9EtlOyE7q6WDsl/Cdi2sc6CNT6+7jbJkiQYW8bfAovALCL/10S74yVMORGM0AYC8JzkCgYEAwPewn7u/gEzeyjurf2HwBCKm42wRyAnhTVlLLX2rCcB+h5sSLvCE+g+GMWSA+OD9+tlt+EZ4W6bzUR4vCFT2X+tW8Fv60o1qCw6YnmiuK+D+pdDNmabkabpHdzM4mfRcevSNbWtF1f/h/W6OpMpTAyHJzaaAtgk5Ut1zSelw2BECgYAi5Dpudugvla6wv1JKMnXPYvmylUXJlw2FGoYqZVzsmnbwS96risnlI+URUErItBQcFdCAKiYY/1JsACW3OSFvghW38nCY4h4765Ij8DO1VHZatjLqsMcJQ9FAX1dTEHbPHvFHKLv2Jf4BovjYQyHdDU3AXmd+UgyJbzYYhiGttQ==",
"exported_keys": "a2V5czo6QXdFVWoybE9oVXFUYzc4NEtSUGxQWXpMWmdiMGtkNC9sZkp1U1BEMHhPZUU4S05BcS83cWhNWnFyYXVIMVN6Y2s0ZVFZZVpqMmoraHpDSEFLUEZRSXpEWERoSHVhbTR1MmFHSlZJRzhPTjBXYmQydHBBMXV4dHFqeWl1OUUybElocmRMRE1mNzBMWWRjOHBkcTRteFM2VzZOUXBmbTNoYUxHRERuL0U3MVduZ3RGNVZLalo4akdqZDF3bTF5aDhkbWtsRS9UbVNONjlMK3lLL014T2hPa1U2b2tHSzFXVlhqTFI0Tm1aZ2I2YTV0QnJJRE1EZVFIZHBkRHhoZmVkeTVjc1NrdVM1Y2cyOHU4NzlHNllqdVd0c2svRm1jeE53cW9qMU5JdTJNdGpJb3ZkVWk0aEh6ME1Ba2lWazZTY0dvQzRqYVQwSlhSVW1qSExqTGNpU2FBaEFuOVd5eVNOazd0R2tJb2FrZE9VMjRYQ1ZtT3hzb3dVLyt1cm5zcEE1SlRQc1BTc24zMElpNEJkS0E0TjJHT1dsVFdsZU03L0hpTTRWTEVaM2lRbjBIMUtvWVdodlVYdCszRWRaK1ZmL1RuYk44SG1yTExnTUFwV3o2RWt3NjNxSzV2bUR0SnpORUkvSFFZeE8zTktqWFYzaFRyK0VZZW9Ncy9DSlI2TTMvQ29tdHBQN24rTjhSRzd4aEwzOFl4UFBWNmtySEFJUWxrdnNNQ1ZjcVFOMnJPcjV5VFd6enlxVHdkNVd5aFE5WkRlTWxObWRxMmVkRENsRzFESkNLN1pnV09MOS9wdlBOUU9TVy9CVW9odmY5dmcyNVB4ZDJHWkRLakpXRHJwYnJxazJQWnFFeDZKa3dRdXJpN1hLY2FOclBYYzZaU2FxalNMeVgveFhMUGtkbXpzSjRFQ0JySzNBaE1MeDFidXBnRnQ5Z3R5cVVOUzBib015aGUxNjQvelBlOUVzMXhUZUJsV25SQmNHbUN0WTEvdTUxdnZ4VkNCd2hZZTY4S3F4am8ydWgwRThIZnBqbWJzNDUrYmIyVUpQVmFteGxkayt0YkR5NmNWMWhJcjQ0N3VGdFpNMUMvSnFEbUJaSHlVa0pRR21kM1J6VmVjK1BmcXhuMDBxYXU3a2pDKzRQTWkzWmdETDBXa2twQ3diVDBGV292WVkrYXVJcjVFMW5QUkdUU093RU1hVDc2V0FTSjZscFJsOFVnR29KNlRBVjJCMzJTS25IK3ZiZmdpVnlxYkxxUEFQOWFaTnFBYjlmUmFEMmVPL0JxSjh2QXkrUVZ5dHB2ZDFxZUNJRVdyaTY4ZUdGaEN1RTlRdkEycUVrZUZBSUtIeERFcS9SZnFHSXJBQnpBbTdmTmV4a290WDVWR2VCbFkwZ2FDOTE0NXZjZFBRakwrMDJJNkFQSURFRTdoSkF1UGc1RDlMY1VNamlydUY4ckRkVUV2eDhvRVVxUW5wYmtkaDlNOTAwQTdJNVdQYlIxdkN5ditVazJVT1l5WmNHa3psUytSYmlsciszbDFXNkpPeVBaZnpTY0Y1VGJSSkREdTE3VTFXVXRvN1VwTGJ5bWZhQ3g3ckdoZ0svR0xsK3ZDb2VmQkRVcFVUb1RuUFNSMGM3YVVYNDZSYlhtMGd5bEQ3ZnRMU2NxMDV3WVNmWFF0QVJrUUxJcmRLR3FKR1VVQ20yZVBFYjcvcVNwbVBTR0loR08vZFpUTWdMWDFnUnZiL210NWNFcDFiVWxLeHgvQmxsS0RtQk9GUStTbzZNb3h3bjF4NStpZ1VrVnZZMFBtMnI3d1J5RTZkK3hyeXEzMGZGbDBoVE9CV1hzaW9qRVBJQ2MzOTQyczdZY2tOSGN5N25qMnhWT2dvSXNFeW42bUxMeEwxTjhPUlVpWC9PdTlGU01QN3VyQlB6M1NaQkpMVk1yVDNQeHVJRUVYaUZVV2Y4ZVF3cjREakllWnJqUERwU2RtL254VW4vS24wQ1lIZHY1dWpyRjAycGpnQ1dQR0twa2FZZ1F2eEZ4V2t4d3dTQW1pWjVlWTlpd01yWXZpaFV2eXFUeGpxNHlYTDZqVnVaVDFKUWtTeFVOVnBFZXZEb0h0VGtIS2UwcHhkZ0lERXFHVlNOdzdEckZTYUI4VjRyTjdjN3FHRWVGOFBydVRUYnltRU5JRWY2SWNpOTR6TnVyTlo0Uzg4eVNqK1NqbVRKZW1PbkVjWWZscnkwN3A1bU53RVRLMFNvelJZM2lZOTFlYlUxcVFWbUd6TVBNZ1FZZkhhWUQ1TkdmcFN4TzZKdWtOS3o3VFFBRXJxUVljaUhISnQ2bTJpditrYUQvRHBmSGhVbkU2M1N2cW1pa2J3cTJaNUkwQVNxS2tVWks5YzZXYVo3ZXFCdGovYXR0RUhuSVFGUlUxdDdEek5wMk5hN0tCN1RkTXdQR1lpUnRQQXdTK2tjWTJSRXJqQzRTLzdPNk52S1RFWXVCTktMM1o2aG5JLzZoQlgvMWZ1cUdSWkRWUlhpUEtyUVRxNHJXcmJ1QkJrbzdQS0RUMEkxWVV6ak5JRWtGblh0dHFadmhyM2svYU53RE55dUdjNlBLNFVZMk43R3BrQW9wMEw5TFlYQ0xDeHJGcis3cEZUZW0vcCtnL3cvc1NuYzlhK1ZJL1Fuc1VMSGtJYkp5NmI3WGZEcmdtZmpxZER5ZTJCL2taa2ZOS00vYXBDTUloL3hKVG16ejVwd3Q5eXZBa2ppYnFHTElSNXA5THV2RFBFSnRCRENWa3VTazhJRnhCM2U5VExoUFlVdXprR3l3WWR1ZmVLdXNaNlFJcHRwNjFmaHF1bHE4UmQ3cEZRdDNMUkQxK0F0RWNCZ21hc2lPTG0wZkFWdmlIa2t4dnV6TTFzMUlleUc0T1JCNVhiT3kyblZnbWVweDBLSVlNc0RCSGVIMUd0YnI4SFg5a2xDYVBmVXZDb0E1dVBXYm9nNkhIZFg2Y1NvdXh3UUFqbzh5SW03Z2RPWlRKOFVEQ0JZTi9GL3YwaVdXdzdGWUw5dXVuUjBSNWNtS0F2SDdoVG82S0w5bW5sNjVWc0lndE9YUWVsRDllT1pHZnJTUkZoQW02OGJYdGdPZUxBOXZZclkrb2o3U3pKV1JGd005dHZGUis0NERkR0pOWEtjT2w5MzA0eTZtYzk4anI1alZDNEpXYVVuaTgwVHdIcUNEbUhDMWYybUJWM2xaQjczbFNna1cvdk5paDFQOERNMlp5Y2g4Sm1WaGNWeWh4TjV1N0hIa1ZrM2E2QWdTSWs1UmpkYUJaUERKc2tYYm05emV3cDdxZnNTaUtsM0RBODdPQlhkejBSSmI1dWFKOFQ2RUhxb2tXTTY1L0lWQUR0Z1VaakJuVmUwdzg1UXJzeTBCUTgxaE85aDlwdzk3MVY3bitmaXlrL2s0NVdCUFAwSWRsbytkWGRwaEY0WnZ5Zmhubk9BZUN5RWNKUHV5SXdkSHZKSjZIK0RNOTJWc1hRZVhxYWd3SHEvb2xQanZGa2hUdlI0WEZHeGpHZ05BRXlid2tRYU9EUHJXbDVZNzVBNWlyTlUrNkZqbFV0SkNUclhFVGh6czU0Y0lzVVpTVXcvWEFzeGI4dFF3TFd5YkVDcWUxY0daT0dJOTRTbTNsTXFvYkRKOWdnWGRzaXMvazFjdjRYU2E1ZDdJOD0=",
"authToken": "D3OIuChJKWJ6L3YjWk4h",
"transportToken": "MIIBCgKCAQEAv85pKAmP8RC1LKq1FG8acSLhCaot+dSEbqPQxCsWJNdzyIeg1D4f\nwH6DSD/+x/ARlKVF+eLwUpVWqVFo+GbpCXkI6emnYwPDwvqkEMu2i8NX4HlzQ9ZD\nDsZzuYafZLBSeHQtOdqBzNEIVHI9tic5QjaKGFGSWjNegObh+vdRJJhDcT/lEZUe\nrOKPHzXVZfTGqWiNoUOZh1jOuJC2khJYsjGjtWutp0kbnB7hc9r0oCtnQ/ebu3sF\nUi61GxPJtrW9Ihw/jfnJN3DBV6NukLh40FAfN+0RbzAtsG665gWtxAzK8+FjL4rq\nG8tJg4cggC1rWS7hxSddc5XjANc6kfBvYwIDAQAB",
"contact_key": "MIIBCgKCAQEAn3/t6fX9WwdIYjT5epftgrXjK1fwG/82HJDHZBasx1fOjOilbRrgiV6yB5XYnZuA+XkZJJOIqNP2wuZnCol5NzJytqmSoUCFDFvDlDcVDFsnbIaKQcD3diS7ZiEDyYcT3nk/0/w7dM2Kv0rj/DAWhtwrvrdCTMLco+IurYP+6vuGDcE2+jjvS0+Og5UTvjLpUAF5EmjMFzIfnkFQNplrkqFJr/m9j+0H06+O0kXN/C0dRgLDhAsXkLAIR1Ptury03RB9n7li37dWMHgWsl4eDn6Mv4fbeMfNcEGU8/gxfzm5dDu/TGkT+jRhFQwOFSsp24AqaabxuJFMPrhr0oSnnQIDAQAB",
"privkey": "MIIEpQIBAAKCAQEAn3/t6fX9WwdIYjT5epftgrXjK1fwG/82HJDHZBasx1fOjOilbRrgiV6yB5XYnZuA+XkZJJOIqNP2wuZnCol5NzJytqmSoUCFDFvDlDcVDFsnbIaKQcD3diS7ZiEDyYcT3nk/0/w7dM2Kv0rj/DAWhtwrvrdCTMLco+IurYP+6vuGDcE2+jjvS0+Og5UTvjLpUAF5EmjMFzIfnkFQNplrkqFJr/m9j+0H06+O0kXN/C0dRgLDhAsXkLAIR1Ptury03RB9n7li37dWMHgWsl4eDn6Mv4fbeMfNcEGU8/gxfzm5dDu/TGkT+jRhFQwOFSsp24AqaabxuJFMPrhr0oSnnQIDAQABAoIBAHrG70z5nl1D7eQrAx/rc1j6yjPDLYFfoze5+sKA8d9BKC4vp6ek2NLlogVUw7oOyek/3qrZJolPINRGp2rlB/oFS2hwf/7Au6oXuSWOgRVR1bckmaij8dlvzRGAuHmZESJgE1ILB3mR/wvhij3GhpCpSsM0LkUIeu9sXKIUyVX3sH53sKaf2Gp0sI44ZV9v7nXa2Ob2AzErE0ZRH7sCmFxT/rEIQyMfQuQRzupT0zgjsCvko87rd79axL5O3Xu4J6L96+fOoOri7kKZzNZEsmvytko1wIexsDIWytEsIulatFyvIrbiaGsO8Y/1rdEBT5wT7Hw+GD88VWB77JipJ8ECgYEA03ezvwVN0WjKf2ScqzQNz9FhwAFb0L5AB7CSat6d4nADZD30k8OD1DNr8dKfhCF5n7qCDenEL3w3APApEWJEpMrZcYersvzPziCbgds5qaI6I2el39zV5LIE7+4Keei25Eder5jZYVQSE9JRscnaOj4Qn3lnTe4bqSgnjOmxlgMCgYEAwRaeufmLO7YfRNsMSEQ2FFmiU89z4eXSz9KK5ZtcTNCMtW9jACuOcEKLSobSOeE+IANmUsX2VGrEhFS2nUlWrPWwMSt8eHb649zU88EM3WbNINqfboJwcsBP+/Ce8I6lwdBeFEyAhLT0cfcZ2q1R6D1d9jFkeno30366sx+Zqd8CgYEAnKIaapAkLss+ypOclBcvb9I4ZD7dYkW5Kbj5Ct2v9oxfhr15ToXQPLqF5w3Kh9U/wDcmo+WWIlIQb8pzsOOn0qRJ4ZTLcf1ecuCmLs5R7Lsz8wuPyrxJVmchzxHzgo8EARx4HvrJcRUTeskbJ+RKlz9nkqgbA5ctt+L9QJvMpT8CgYEAseUBQB6lJNJaZLnbywjtOjqKz+Slw05Wt5om1fwZQbwyp0aEU7fNd6gXZQZp0WGwNxZqw4AXvxbPD4xs4uSasqd5ORPzjZkw9ZaTrDAEhkccXlSN5ubOayq7hkbeaItENBihVNpW3e1J+WXLsClW+TzwwM4o4J6RqI1tvXIzxMkCgYEAxTEpgE+ArTBUFI2dE5SUuzizqgXDTvX+oV12noTyA4QhWK5Ood/so1wwQlYgPQfWCRtB7jSRJCN+JCCN8RYZA3tBb+YnvEDK3xp6ijpK7p9B2BU0LGxclaO9WYdeE3zfJxxf2xobduHvMgyqGqGfkia7DtxR9hlu8LyEfSQKFkI=",
"exported_keys": "a2V5czo6QXdISzRDWGJiNUIzWjFYemhqZ2NqanljRTRSY1lOcWswQ1JhZDVPWEZ3bEJzelFNQ2V0N2hYclBBSnhkZkxPaUdleGFQMUMzc24wNkdOS0ZFcTFBQ256cGVQMXh2VDlHRnE2bHEyOHNyMFA4Q0g2S21qUkVucXI0M2k3VTgvTVBKMWlHNFd4UHVCMXdadnZnL2tVTGFnYnkraE9TMUJaUEpIdkNBUTRXUXdyRVFIL0YrNGZNNHdENEwvdVJ3Rmx3YXRjeDExbldIT2lBVFVRbC9MejByRjYwcElQMUkvYkZ3ZVcrS3BKSmhCU3lnWDJZMWRSVXc4MHpuYUhLWjFiQWxtNHZVbTh6WDhxb1J0QmlmSFhWbWRNQno2VXVyMGlwd2ZMVkdaZllBbHRzWEk5a0gveDBRaEdRYVE4QUQ0OG9JcWVQdGk0cG1FZ1hwdHZWS29EejBYcG43ekRBVFNTSGg1RnB5djJ6MVpmZWxIN1lPeUx1clpwNjh0R1h2b3VMWTFQV0xSTEdkTFB6RWNVQ0N3TW9jY0ZaUG1JUm1QMXVublRmbjJ3YjJDTlBUTXpGdlc4TTVGYlJ1TG5jdFNIaXNOVWN6TmlKdmpXbUJkZTdUWEc2WlZqc0FjMkIwbkQzaGxiSE5vOGlyRFhibmhwaHpOWnBneTNTMXJwdTRLdjNKNlJtazZTNUd5QTVlZDY0U3FaNitqTFhqUjJMdm4yTitUYVNtSm1may9tMm9VRmltT0Q5RWRZL1VORzFpSHNmL29vZ21lSkN1c2d5WnprRWsrMW5rOWNEWHlTTUR4VVFPQjFscWZkN0pPQzNHc09RbElETGUzOWZVemhXM1g0UmRGakhNZVBHUU5uWkh2MkV1TzRZYWp5ZVQzV29pdkNyRUwxSHI0cEJZMUNqenBQSnV3Vmp4eGRQOWExSmtIUmV0QVJ2REROYzRsNzlVeWk1cm1BMnN3VHhvYnhiUWlETXNwZVBIY1U1KzBXdTVMc0JNWmU4UlBHUmRBc1h3Witqdk1QdjRlNmRuWnhzdGZvTjc1OElReFhDWms3Vlhjc3dYZ2VjU3oxTlFOYmpqbEFoMS8zVlBCM1hYWWZqZGJyM0cyMHJLYy9wWXNhS0lITUkwVTdnYldYZWxuYmRVajFCdEN1Y2MzT1A3VmZLWWxtTXQ1NEh3c2I5N1oveXBzb3M4NlU1VXlWYUd4eDBWZklaaWRLMVVXUjdaSEtXR1l2WWRyOGd1a1hqaGxmbUh5MFdHaXBkcVVGS0MyK3hnRW5aSm01SllVS09DVFMvMTJvVkd0NjNOaU9xM3pHamI5c1NRMTVGQ1BJS0laM0NMbVBSVXBBcmU0S0QySDhNSExHdGZ0aHA3TlNWT3d4cHAyRkdLdFJyYmlpcmFidEI2ZE9ncHJEbjZGYVEvcUJxOE5Ld2pIUjhTdVF6dzdNdXJBeExPck1CSG91dUQ2dUdMaUY0TU83WlZURUt2SWVvSGFwa2xMU3ZKcyt0cFRRZ09JTXJ0U1VlMHlvTm8xRmF6YSs1aU5MK0pVY0FTTkcxcEhLVWtOUkIzaS8vQXplQVNBbjl3cTZMZEFjTk9sUlN0ZEhUZmdueEFjZ0x2L1JBcUVEK3FEVmNUZEdJNHluZ0dGVGJvdWttK1NmQ2U4Q1hpMys0amFYekVYMUVtV1FKMGMzZE9ndGZWcldVSjQ4UXNnTk5iSkVSSHc2QVFWNGtmWjZWd3lKVGxZV2licHVPZ21PUmRJakJuUlVtTlJoNmRUSTd1YlN5TnhyWG5GWmpzcDlrMjNTTXFpNGt3eWVvWkpEQklPeTMram4weGxHV1lDOUpzcEtDY0NreWZGbk8wWFV5SjJ6NzRJZzRmZmxvWGhDelZrT21CTnhIOXBHbnNNS1ZhMDNuYWFOZFl6RWNOOS9sZjR0dUcrMFd0dFVOTVJZS2s4YTMwUUo5MXVTWmlKZXpCVWd2bndRSmtDUlBWVDlIcTc1T2ZiODZjT1lWSGlBVjQwSzl4L3p5TDdsZ0JFeXpDS0lURHNQS2RXcGZtclpNTVJndk9pdEdUcmhzdy9LNjJ2dlBFdzZhdGFDVFZ0dGhvSjZpVUppS3VmSjF3UlErclhORTJOdXZmaW1pZWJjazlLNldaaHVhTXc2WkYzTEhiRnNCOTk1TEFSTTU3QlBtZDU4d0IwUHA0Ym1EUkdDeTA2dmd0ODFQSWllamF3dFZtOFltRXJNdlIyOThTWW9RUWVDZUtKNDl2NnpzdHlUaUFtS1dzV3JxMnN5d09EUVZnREpMNHh4ZlpGQ1RsclU4UnZkMDZIUDd1K25Cbk1VQVptRVlqbDdRaHZ1clRPUTh5WDlKaUdMcDBhWjl2R3pwa2RqSjc4d3k3UTRXV3V6RkRldklWc0pPUVNPTkt2K25hdWJFTm4yaEFKUExET0lzRnE4SmVsbXc1RW9ESjVaRmNjM2ZQL3dNL2JoYlV6WHhqWDhZVm9ubGhBSzlXUWo0aU1PYm1WS3RTdldyUk9uZ2gwZVFITlBhQnJ0MW5CbHM0NWZ6emhOaFpOZFpodUhVQ0t6QzlhL2tuSElhNmRQNTdaVHVRUnVCeWExc29XYXZ6aDV4d29IbDJ1bmFCZ2FSUTlkYURUaFA1QTlaeXlIUEM5aC9xSldnN0dackQ1RVV1cFZqamFNMm9wUjBYL0F3Nks1OHRYTUV0aU5LSW1zZWJEeEljK0g0NjlSODhXUUNONmJtUmhFR0lwMVk1bzlQYVBCOWtRaHJIUjlNcmNSc0dWWDVGMW12dHlEOElnYVh0VHprRktKSzIzdHA5Vm9yZjFrRDVMTWxsT0tva3RhV3E2Skd5T2ZEK3BzdGhTV3BDN2Iwdk5xWEZVdkorNWs5cjVGUWJrVEhhMHpVVTBHNWhVME9mNnBIRC9aQmdyNTFwWVhSRnNwMjZ0M1RMWkFBbjBBQjNmKzk0TnczMjlFQXI2WmdRakxwdGJqQUlsdEs0T09zVFVIRlN4cHhJMXA2dkt5c1VwZWt3b0c2a2NsQWRYdjBrZFZVNXdWWi9ZMGx3eEVDUWt1TFFDS2o4ZnRnY0NoMEVuQ3JGNEV1VmJ3TU5jRnZBVXNVUFAwangxWkY2N3FveW9iSHYvRVpwbng1RTZPYWJ4c3ROb3N0NXEwbit1VER2aUdUeHZpSURyY0lFeGlTbTU0dmJwTzlIWFNEanJYT1BkTFFhVlR3RWFmeTdJeGNzT28vZnJNdzJQMlExRGNDdVRMRW5HLzNBWXFNMXpWd0x0L3pVcVA3OHlFeU0yTVBxNTh5cG51Yjk4Z1kyQUdPUFNaNzNHME5Eek5aQXJtMytWRldFeHRRQzdSVGNlQVZLYkgzL3d1ZFlYQ29ObW9qRGVZZ01FUzhUdUYxV2xLaFhqcmgzUGFPSzhCZXBMeDhaWjhUTUd6SW9vU0lhWjVMT1ZZMTYyZFZZOG8raVpUa3FTd1RaSVozTzJKUUJ3YkxhNDRmelJFM3lzV2ZqNExyNm1YNXgwMTY0UGNDdndNdk1XTmFySi9OV3R3OWJQcDEvdnp1MC9oWmxwY0dKNzY4UGVCREtROXNsYytmVVdHdFhpMWZVUVkxRGNGSndOWk55eW5MNEtRNDR4MkwyS0JGUXVTeFdxaExNV1VsTjNHaTFFSmp2RG9wUThNaGpLbz0=",
"pin": "111111"
},
{
"pubkey": "0382b91f7efd6c16c551d54096df7a20f66c2fd29a8da39ab237602da4ad7ff76f",
"routeHint": "037ec785c6004d512ebaeb0020f81a2bcdb6fccc9539f7b891f704289ebc65a4e3:2199023386625",
"alias": "virtualNode1",
"ip": "http://host.docker.internal:3004",
"external_ip": "http://localhost:3004",
"authToken": "17HHEVkDq5YrT6knzumM",
"transportToken": "MIIBCgKCAQEAv85pKAmP8RC1LKq1FG8acSLhCaot+dSEbqPQxCsWJNdzyIeg1D4f\nwH6DSD/+x/ARlKVF+eLwUpVWqVFo+GbpCXkI6emnYwPDwvqkEMu2i8NX4HlzQ9ZD\nDsZzuYafZLBSeHQtOdqBzNEIVHI9tic5QjaKGFGSWjNegObh+vdRJJhDcT/lEZUe\nrOKPHzXVZfTGqWiNoUOZh1jOuJC2khJYsjGjtWutp0kbnB7hc9r0oCtnQ/ebu3sF\nUi61GxPJtrW9Ihw/jfnJN3DBV6NukLh40FAfN+0RbzAtsG665gWtxAzK8+FjL4rq\nG8tJg4cggC1rWS7hxSddc5XjANc6kfBvYwIDAQAB",
"contact_key": "MIIBCgKCAQEA06nUL+xYNW//CfAoLn5HzZvgd7qiGznHtCZz5yFDTTSFfUk7mOpy+1eGnYjivKASMFFbgg+KGCqXO7JYlb5LG5zzmriHMbk4mXkPJQKR0X77cobjjkDVOn04TbkEpFVP2iUKAA/jWc3iildS7yLtni6RHtZ0cNhnAC5D8I3DuJA1gzuIMPo65CShyJAmGtY4xm0p/+0NtaeNnlzrNrvFAR6h+MXoBHgqT+YidMO3uSLcO+9V37u5Bd4VGEWEgoZYiY2/mOWilKNoaLoU0xPJMb+i78w+otizlB5jlSLWAXYUdLnl8JpjPmH6R1jNd3Kit+8p6mx2Ob0CCQ+wdqKJ2QIDAQAB",
"privkey": "MIIEowIBAAKCAQEA06nUL+xYNW//CfAoLn5HzZvgd7qiGznHtCZz5yFDTTSFfUk7mOpy+1eGnYjivKASMFFbgg+KGCqXO7JYlb5LG5zzmriHMbk4mXkPJQKR0X77cobjjkDVOn04TbkEpFVP2iUKAA/jWc3iildS7yLtni6RHtZ0cNhnAC5D8I3DuJA1gzuIMPo65CShyJAmGtY4xm0p/+0NtaeNnlzrNrvFAR6h+MXoBHgqT+YidMO3uSLcO+9V37u5Bd4VGEWEgoZYiY2/mOWilKNoaLoU0xPJMb+i78w+otizlB5jlSLWAXYUdLnl8JpjPmH6R1jNd3Kit+8p6mx2Ob0CCQ+wdqKJ2QIDAQABAoIBADhs+rr316APRj8g/aU/VubyGgnxAAwgACP/aECCdo2bZca7gh7GyXZFpAZVGpTMW2z0E1/9woOkvwJUDheFTkKDOdHSRYA072jChA4KvFLL9j5WxU0D7ZQVE7BslVc1wv7Vhu/zTFmBcFYO53YGqq/TnC5LX2lB11uN+eCj+jw2AQSHfiTisGkLxWbhVulK7zoSs1kZlfbseljaQam5nVx+We7QrCXra2A1AY4SPWA1P65fEAyx9XQeH6tz8uh5RPIixXp10K4mkI3oJ+WakCW/rImG/4+16E7rZV6iQZs6EYLMOa5/5ZNEoLrepniLfj3thMXgw/6KD5Ei109DwF0CgYEA+0nMdhpZStW4F2GWAExDQOWH1MxgIRhseCB5+fvfRNu8Zw3nSYsBj9pdwRhHSs/3BatjUoWuPt0bJ2AHq9tnpOv3TNSIRQVhsNqYlVfyoFnelhXMzpf3P6IzlteeGeMqj/yjC4ocOfPrWNVnV5W0GFvLUEhC/RM6XHe3ya8N6HsCgYEA16HT9djICra5WCXoWPcmbU5tThzAadg7Ofy2dp14kRzJZQb+hNLDnUrm6MvlCk4iiQM9Em7fzVPkF1NJ/PxWnFsGH5RUDxCURofkmoTd75cK98NdrvsT+cWj/jF41UytELppdXm8+hs0eRk28Hb4MBtZP+AP+qmbzdw2pcrrqLsCgYALJXPfTT3mtuIqj1aS/s8A4u2Kf+JHtYiiL3aZoxV9PW32+EPpHDReiCYeeZA3/k+LvdVzBKD9AtvAfF76vYm0ZA8dJlRBE4MI0DlybmtBt5rK936VL2J1PSGisD/AEDaEGoW07lRgMbSfxR+HYAmUBwZWsk3eYer1zQ2m8Y/hXwKBgQDWy+I7fJVQbtJUJ3a64H9L1Rr2+5cEGJxu1/jeUWCflMBdPcldgCHR1qIL9ceTK2Alga9dZErV2yJTxejm9GpGWDnSTUwqsYYyd/3VmlMF7jzDr73rpzovzZvdg2RtfXLMPhT9K6Z+sYjktKRQhwIV0bhm84iXVkrYluts3aVALwKBgHUk3IU9uCyXG/qAORchWU3ayfMU3cOY5X6XhR7rX+PTX6IeGrm5W57Nm3PE1+eXOSBhV5whGhIL4e8x+WOgXmRe/oS4lb0s/9lDjuwVqm9bix/psmYo2pIHhEceT4xpm9ydFiSTF2wNLWz8SIRJmApYts1TF7eum8F+J4wtAopU",
"exported_keys": "a2V5czo6QXdGYVJndVZ3eFcraUdNM2RZeHJpcHJHSFU1RnBpTnoyRUpuN1I5UXpEVHZYcXFCR1ZxMCtpbGV3KzdibHFwU2JpeGVwOE1jZEpBZGlCK0xpM1BJWHhrMjUrZ0VaS1BXRzA4SDJBNGFDNlRCV0FZRjBGSFVBVDBUOVRUdG80WDlwTUM3a2xRRWNUOHM0djQ2R1ljL1BpL1VZT2lVK3VpNmgwWlN6V3phYk9POTVtOCtTay84ZXdkTnNZdWtxZnQyRWFIWnhBc1Vzd3J4ekV0bEpzcjBSc1kzNlNPdkc2bklNV01uRWxNdy9JM2hDSnBEU3J5M015R3lseDdtK1JKS2VRSW5NZkJ0S1hSbGgxMHoxTHdXSmx4eGxqODFsVFplMG1KQ2l6bmduaVVCdEpjdXkxY2p0dnI2WW9ZVHd4M2tpWDlsVTRFdWY2L1FMTUhIcFVMajhrbnFBRlV4aDQ4aE50RFN3bHZTTUJkdzhXTEZzN1FjQ3NNZ1hqZzNYNnBybXRUeS9vQlN6Mkh0YVc5S2ZabHhJT0ZIYTFnS1lLTUlTVEphYkM3SDA4cmFaVmZraEd1ZnFpbVE5aFRmRTM2YXNDSUpFTXFOTWdRV0ozS3VNNUtsQVhzZnVzNjZsdTJLL29ERk0vNmluQVltWDE3OXJVeTZqYmlpbjdYM1FIeHEwSW1NWlEzK3dWVlVjUXluTDNDNHNSYzJUcDhnQUxDOENkVmhoK2JZLzRVNlV5b2J4Ulgxd0NnK2pvR3NScVpyRXVSaWROSWNuVVNpSyt0TDg3cDRxMHVBRnE3NmcxUU5FNHMrUFZOOUwzdEtwblJJb2ovTFZKZ3JrbWN3TW9tQzM1ajZibzJVWnFneis1Z1Nqek96ZC9aMDY4azdtaFJIbzhrOXJHSkREdzRsM1FHbzJ0MnVHd014VXVneTJFbnBqMHE4Sjh3ZG56WWFqcTVQRzA0YnMyL3k5aHp5ZTFEbzQxaDdFbDlnOWdUb0lSeVE1djA1TDM1Ni81VlBQVzhiRThWY3grQ0Vwb3lSeXB5RktUOENaczdaOUJYdDd5b0VCK21yeXdCUk9lMUhoVUM1VlNmYWJLWlh2YVcxRjJlcktMSFJpQmNWbHF2d09zWTVmM2ZQcmRIVFdoV3ZrR3JqVVJQcytwcjdaUXBpZzlGN1BVUlFTWnVmQ1V4Y25pekt0bHV4YXdESm15Uzd6QWt1cldTWmNUb1hId3BtOEl2dS9PZnpJNVB4dk13V052c0pKY3lqcmhyQWZWajNtN3BUZ3VXVTBYbTEzb3hZenpFS0xYUk9ZNnhSWTNMaDd0dXhkVGRrN0w4NFlndnVnOS9CNWJzcC82d0srSStJRTdKQWpjREtaeFkyMkpScys1RWFQbllCdWZpeUhTdGxiUXUrK3UrblNkTzZOclBEdlBESHRwTThEVW8vemJuR2lYM0ZHZitBakhHcHlRN003c3FsMDAyQVkyZTVvRnFVOHFPSGdtY1IyZnRIWHZ3c2lRNS91ZEdLWS9JL0l2SC9pelhLdEErcVNCb0lPYk1pN2QwT1NZSW1VUDdqbHpUTEpuUlgxVExrQmhGQkhvdnhpbXEvWEtsT0kxRUxWMkpwZVhkei9FaFFaS3VSRDYxUlVVM29Dc0g0a3loaTdJMzRtR09vVjFBTmx0T3kyUWtKSE50RXI1V3VuMWxIelQ3Y293SVNsellublV5NkdSdHlzRWhQMkhnTHYxZzlhMTJOSE5OQ1hjUmNRUVZaTXB5Q2JmQ2lpeHFGOWFLQTFsN3ZvcG5kNnhGYW1ld0pYWEJVWG9Kb2wyS0hyTWIxZmJ6S1FpSFdvSVcreGlOd05RaTIzRVRwZUMvSlg3cndPNkJpK055NjVGTExvWFAyQTZYSVdmVVlLV2g3ZVVId3R2WXFnRnhOdk5oRStURmViaTdDVWV1a0wxOFNqRDVnM1FXbHFRUWtxajQ5T2FnWndkSXp0WFRNbzdmYXhGK0xoSVozU3N0T1RpN0ZSN2J0bDBUNkF1Y0ZjY0Jic3NhTkNGTFJiWFJyczNac1NJWUxKWHgrYkdQUE9walUyalRKemI1UEx4NytzRVZ6dEtUOHhDU1VQNFZjVktGOEQxVkhQVzJLM3NUQlNId1ZWa0ZxK0lBZ3ZWMG5mZ2owaUtJWVNyci9jNjFHT1o4ZUNzb0VJUTVGWkJaMmprNDZCRWJ6Z1grMXZNZFNtV2NRdXRBUTJQRU00Q2FFOEJISWF2T0R1U3kvbjh6N0xNSnU0Q2tDeXIwbXdzS2thYmlzSkwzL0ZvZmc4QnhjNTdBeXpPcWg3YldtaHlhbU1DWHlDcUlQZGtHSG13WUd1SDRoVXlWaWdoY253Y1RXNzFkT3llZ1NWTDdSMEZvVFEyNk5QVWhRZ1FpWG9UQkJLS1BKZC9NNkVzeWJMTVhDVEZzc09mOEM5N3pMZXdMbXU1OWc2VytoQ01IY0ZoOFJXMmFicVluT2cxRk9yckttRkpFbVAyTU5IaDA3QkxKT2RWRkJZcWNLTGRFNGVKNzJtZnZVbFhiUGUreExEb3doM1lPSi9YeVJESXRwVHRsTUhGNW5pL2NwVGxkcy9rTUFMZUZ0d2x1ZGFucDdSbGJZc1hSSDdWVnh2Z2MzUVdQdW1jK25DYVlkWGZUOFZuQ3R3RDBqRXJMbmdrYm9Cckh4ZFd5dXJRZmpJa2NONy9CaHFIMThON2hTV3ZMVVJkYUYxZVlFSlAxSHVsclFXeXRQRkNRcVlwUVZQTFJaYmlNYnp0YUQ5VUJuM3Y0emFSb2p1NTV4eGJiVGxCbkJGZ2hLWlIrUER3aXhoUVd5OUtlRGZpRjlKMjlRV1B2Nnl3WHhyWTVoS3g5d3Yyb3pnMys1MW9Vckc4WUkxR2Q0SXVuVmRHKzNqQW56a0lyV25wQ0U0T3BpeXRrVHlEelVHSFlhVW5yRnFIMHhCcm1vQU1GNmQxVXM5czU0MW5EUjNPZkJHbHRCcmhFcE1SYnJVV1VYbGpKVVd5c1RvYjNGOFNNd0Y2aGt6TDcxbDRIdnVtZnFmdUxrQSsvUEV5WWFVdGplRFNnZUYwcVpWSDZmQWxrbi9SU0lqTkt4aFk0YnJrN084THQ4YmJ4U3h3c2FxTEtuR09LR2ZIbTNqV2VaL1VQV256YjNrWStBblk5WThwTU9lYjlCMWhKcjlBTi9Kd01UcHl5aUFIR3hXK3Vlay8wdUFOYjZzbVBDNkFwaHNRUU9kOHNvV1U0WlowOTZYTnVHRjZabytEUlF2WTgzT1BzbUhBRnF4K1F0U1V5NUlLYURKWUtwKzZVbE5sbWNydXRvR2RXNE51S3dzK3lIM3Y2OE52YWFCY1g1enpEY2dXclNWMVc0U0g0bC8rTW9aSnQ5ZjJqRGxUQW1YeTEyZnpkYXJWRUFRTHA3aFZPZENqcDBxVElPRHZ2OUJNV01IUXh4RGl3SHRpbzZPK21QQ2E1NHphcFdVQ204Y0dLN0RxVXhCZlFWbXIyUStpcDNHc1IxQ0ZmQ0F1SFU1QlJtM3pXeE1DV0xySG1OSWpwaHRoelNJUm1QL0VJWWRLcFpVTTJTZlptU2NFekJoTm5kNGE4QlJRZnI5VDlVNk5FWXJZM0c4UCtPUjRKbFdadjdkNXMxRjd2MFdKVmlPdHZvQjB6Tm5nUT0=",
"pin": "111111"
}
]

View file

@ -0,0 +1,160 @@
import test from 'ava'
import { randomText } from '../utils/helpers'
import { deleteTribe, leaveTribe } from '../utils/del'
import { createTribe, joinTribe } from '../utils/save'
import {
sendTribeMessageAndCheckDecryption,
getTribeMessages,
markUnread,
readMessages,
} from '../utils/msg'
import nodes from '../nodes'
/*
npx ava src/tests/controllers/deleteMessages.test.ts --verbose --serial --timeout=2m
*/
test('test message mark unread: create tribe, join tribe, send messages, read messages, mark unread messages, check number of messages, leave tribe, delete tribe', async (t) => {
await unreadMessages(t, 0, 1, 2)
})
export async function unreadMessages(t, index1, index2, index3) {
//TWO NODES SEND IMAGES WITHIN A TRIBE ===>
let node1 = nodes[index1]
let node2 = nodes[index2]
let node3 = nodes[index3]
t.truthy(node3, 'this test requires three nodes')
console.log(
`Checking boost messages in tribe for ${node1.alias} and ${node2.alias} and ${node3.alias}`
)
//NODE1 CREATES A TRIBE
let tribe = await createTribe(t, node1)
t.truthy(tribe, 'tribe should have been created by node1')
//NODE2 JOINS TRIBE CREATED BY NODE1
if (node1.routeHint) tribe.owner_route_hint = node1.routeHint
let join = await joinTribe(t, node2, tribe)
t.true(join, 'node2 should join tribe')
//NODE3 JOINS TRIBE CREATED BY NODE1
if (node1.routeHint) tribe.owner_route_hint = node1.routeHint
let join2 = await joinTribe(t, node3, tribe)
t.true(join2, 'node3 should join tribe')
//NODE1 SENDS A MESSAGE IN THE TRIBE AND NODE2 CHECKS TO SEE IF THEY RECEIVED THE MESSAGE
const text = randomText()
let tribeMessage1 = await sendTribeMessageAndCheckDecryption(
t,
node1,
node2,
text,
tribe
)
t.truthy(tribeMessage1, 'node1 should send message to tribe')
//NODE2 SENDS A MESSAGE IN THE TRIBE AND NODE3 CHECKS TO SEE IF THEY RECEIVED THE MESSAGE
const text2 = randomText()
let tribeMessage2 = await sendTribeMessageAndCheckDecryption(
t,
node2,
node3,
text2,
tribe
)
t.truthy(tribeMessage2, 'node2 should send message to tribe')
//NODE3 SENDS A MESSAGE IN THE TRIBE AND NODE1 CHECKS TO SEE IF THEY RECEIVED THE MESSAGE
const text3 = randomText()
let tribeMessage3 = await sendTribeMessageAndCheckDecryption(
t,
node3,
node1,
text3,
tribe
)
t.truthy(tribeMessage3, 'node3 should send message to tribe')
const text4 = randomText()
let tribeMessage4 = await sendTribeMessageAndCheckDecryption(
t,
node3,
node1,
text4,
tribe
)
t.truthy(tribeMessage4, 'node3 should send message to tribe')
const text5 = randomText()
let tribeMessage5 = await sendTribeMessageAndCheckDecryption(
t,
node3,
node1,
text5,
tribe
)
t.truthy(tribeMessage5, 'node3 should send message to tribe')
const text6 = randomText()
let tribeMessage6 = await sendTribeMessageAndCheckDecryption(
t,
node3,
node1,
text6,
tribe
)
t.truthy(tribeMessage6, 'node3 should send message to tribe')
const text7 = randomText()
let tribeMessage7 = await sendTribeMessageAndCheckDecryption(
t,
node3,
node1,
text7,
tribe
)
t.truthy(tribeMessage7, 'node3 should send message to tribe')
const text8 = randomText()
let tribeMessage8 = await sendTribeMessageAndCheckDecryption(
t,
node3,
node1,
text8,
tribe
)
t.truthy(tribeMessage8, 'node3 should send message to tribe')
const tribeMessages = await getTribeMessages(t, node1, tribe)
t.true(
tribeMessages.length === 10,
'The total number of message left should be 10'
)
await readMessages(node1, tribe)
// Mark messaages as read here
const tribeMessages1 = await getTribeMessages(t, node1, tribe)
t.true(tribeMessages1[0].chat.seen === 1, 'last message should be read')
// check that we have less message
// mark messages as unread
await markUnread(node1, tribe)
// check that we have more messages now
const tribeMessages2 = await getTribeMessages(t, node1, tribe)
t.true(tribeMessages2[0].chat.seen === 0, 'last message should be unread')
//NODE2 LEAVES TRIBE
let left2 = await leaveTribe(t, node2, tribe)
t.true(left2, 'node2 should leave tribe')
//NODE3 LEAVES TRIBE
let left3 = await leaveTribe(t, node3, tribe)
t.true(left3, 'node3 should leave tribe')
//NODE1 DELETES TRIBE
let delTribe2 = await deleteTribe(t, node1, tribe)
t.true(delTribe2, 'node1 should delete tribe')
}

View file

@ -51,6 +51,7 @@ export interface Message {
cached?: boolean
error_message?: string
thread_uuid?: string
chat: Chat
}
export interface Chat {
@ -81,4 +82,5 @@ export interface Chat {
img: string
meta: string
pin: string
seen: number
}

View file

@ -19,3 +19,5 @@ export {
} from './sendTribeDirectpayment'
export { getTribeMessages } from './getTribeMessages'
export { decryptMessage } from './decryptMsg'
export { markUnread } from './markUnread'
export { readMessages } from './readMessages'

View file

@ -0,0 +1,11 @@
import { NodeConfig, Chat } from '../../types'
import { makeArgs } from '../helpers'
import * as http from 'ava-http'
export async function markUnread(node: NodeConfig, chat_id: Chat) {
const msg = await http.post(
node.external_ip + `/messages/${chat_id.id}/toggleChatReadUnread`,
makeArgs(node, { shouldMarkAsUnread: true })
)
return msg.response.new_messages
}

View file

@ -0,0 +1,11 @@
import { NodeConfig, Chat } from '../../types'
import { makeArgs } from '../helpers'
import * as http from 'ava-http'
export async function readMessages(node: NodeConfig, chat_id: Chat) {
const msg = await http.post(
node.external_ip + `/messages/${chat_id.id}/read`,
makeArgs(node)
)
return msg.response.new_messages
}

View file

@ -416,6 +416,8 @@ export default async function migrate(): Promise<void> {
addTableColumn('sphinx_messages', 'thread_uuid', 'TEXT')
addTableColumn('sphinx_timers', 'msg_uuid', 'TEXT')
addTableColumn('sphinx_chats', 'second_brain_url', 'TEXT')
}
async function addTenant(tableName) {

View file

@ -433,6 +433,7 @@ export interface TribeInterface {
owner_route_hint: string
pin: string
profile_filters?: string
second_brain_url?: string
}
export async function declare({
@ -457,6 +458,7 @@ export async function declare({
owner_route_hint,
pin,
profile_filters,
second_brain_url,
}: TribeInterface): Promise<void> {
try {
let protocol = 'https'
@ -484,6 +486,7 @@ export async function declare({
owner_route_hint: owner_route_hint || '',
pin: pin || '',
profile_filters,
second_brain_url,
}),
headers: { 'Content-Type': 'application/json' },
})
@ -519,6 +522,7 @@ export async function edit({
owner_pubkey,
pin,
profile_filters,
second_brain_url,
}: TribeInterface): Promise<void> {
try {
const token = await genSignedTimestamp(owner_pubkey)
@ -546,6 +550,7 @@ export async function edit({
owner_route_hint: owner_route_hint || '',
pin: pin || '',
profile_filters,
second_brain_url: second_brain_url || '',
}),
headers: { 'Content-Type': 'application/json' },
})