You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

350 lines
13 KiB

"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 });
const path = require("path");
const tribes = require("../utils/tribes");
const crypto = require("crypto");
const models_1 = require("../models");
const jsonUtils = require("../utils/json");
const res_1 = require("../utils/res");
const network = require("../network");
const actions_1 = require("./actions");
const socket = require("../utils/socket");
const node_fetch_1 = require("node-fetch");
const SphinxBot = require("sphinx-bot");
const constants = require(path.join(__dirname, '../../config/constants.json'));
exports.getBots = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
try {
const bots = yield models_1.models.Bot.findAll();
res_1.success(res, {
bots: bots.map(b => jsonUtils.botToJson(b))
});
}
catch (e) {
res_1.failure(res, 'no bots');
}
});
exports.createBot = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
const { name, webhook, price_per_use, img, description, tags, } = req.body;
const uuid = yield tribes.genSignedTimestamp();
const newBot = {
name, uuid, webhook,
id: crypto.randomBytes(12).toString('hex').toUpperCase(),
secret: crypto.randomBytes(16).toString('hex').toUpperCase(),
pricePerUse: price_per_use || 0
};
try {
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
const theBot = yield models_1.models.Bot.create(newBot);
// post to tribes.sphinx.chat
tribes.declare_bot({
uuid,
owner_pubkey: owner.publicKey,
price_per_use,
name: name,
description: description || '',
tags: tags || [],
img: img || '',
unlisted: false,
deleted: false,
});
res_1.success(res, jsonUtils.botToJson(theBot));
}
catch (e) {
res_1.failure(res, 'bot creation failed');
}
});
exports.deleteBot = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
const id = req.params.id;
if (!id)
return;
try {
models_1.models.Bot.destroy({ where: { id } });
res_1.success(res, true);
}
catch (e) {
console.log('ERROR deleteBot', e);
res_1.failure(res, e);
}
});
function installBot(chat, bot_json) {
return __awaiter(this, void 0, void 0, function* () {
const chatId = chat && chat.id;
const chat_uuid = chat && chat.uuid;
if (!chatId || !chat_uuid)
return console.log('no chat id in installBot');
console.log("=> chat to install bot into", chat.name);
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
const isTribeOwner = (owner && owner.publicKey) === (chat && chat.ownerPubkey);
if (!isTribeOwner)
return console.log('=> only tribe owner can install bots');
const { uuid, owner_pubkey, unique_name, price_per_use } = bot_json;
const isLocal = owner_pubkey === owner.publicKey;
let botType = constants.bot_types.remote;
if (isLocal) {
console.log('=> install local bot now!');
botType = constants.bot_types.local;
}
const chatBot = {
chatId,
botPrefix: '/' + unique_name,
botType: botType,
botUuid: uuid,
botMakerPubkey: owner_pubkey,
pricePerUse: price_per_use
};
if (isLocal) {
// "install" my local bot and send "INSTALL" event
const myBot = yield models_1.models.Bot.findOne({ where: {
uuid: bot_json.uuid
} });
if (myBot) {
yield models_1.models.ChatBot.create(chatBot);
postToBotServer({
type: constants.message_types.bot_install,
bot_uuid: myBot.uuid,
message: { content: '', amount: 0 },
sender: { pub_key: owner.publicKey, alias: owner.alias },
chat: { uuid: chat_uuid }
}, myBot, SphinxBot.MSG_TYPE.INSTALL);
}
}
else {
// keysend to bot maker
console.log("installBot INSTALL REMOTE BOT NOW", chatBot);
const succeeded = yield keysendBotInstall(chatBot, chat_uuid);
if (succeeded) {
try { // could fail
yield models_1.models.ChatBot.create(chatBot);
}
catch (e) { }
}
}
});
}
exports.installBot = installBot;
function keysendBotInstall(b, chat_uuid) {
return __awaiter(this, void 0, void 0, function* () {
return yield botKeysend(constants.message_types.bot_install, b.botUuid, b.botMakerPubkey, b.pricePerUse, chat_uuid);
});
}
exports.keysendBotInstall = keysendBotInstall;
function keysendBotCmd(msg, b) {
return __awaiter(this, void 0, void 0, function* () {
return yield botKeysend(constants.message_types.bot_cmd, b.botUuid, b.botMakerPubkey, b.pricePerUse, msg.chat.uuid, msg.message.content);
});
}
exports.keysendBotCmd = keysendBotCmd;
function botKeysend(msg_type, bot_uuid, botmaker_pubkey, amount, chat_uuid, content) {
return __awaiter(this, void 0, void 0, function* () {
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
const dest = botmaker_pubkey;
const MIN_SATS = 3;
const amt = Math.max(amount || MIN_SATS);
const opts = {
amt,
dest,
data: {
type: msg_type,
bot_uuid,
message: { content: content || '', amount: amt },
sender: { pub_key: owner.publicKey, alias: owner.alias },
chat: { uuid: chat_uuid }
},
};
try {
yield network.signAndSend(opts);
return true;
}
catch (e) {
return false;
}
});
}
exports.botKeysend = botKeysend;
function receiveBotInstall(payload) {
return __awaiter(this, void 0, void 0, function* () {
console.log('=> receiveBotInstall', payload);
const dat = payload.content || payload;
const sender_pub_key = dat.sender && dat.sender.pub_key;
const bot_uuid = dat.bot_uuid;
const chat_uuid = dat.chat && dat.chat.uuid;
if (!chat_uuid || !sender_pub_key)
return console.log('no chat uuid or sender pub key');
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
const bot = yield models_1.models.Bot.findOne({ where: {
uuid: bot_uuid
} });
if (!bot)
return;
const verifiedOwnerPubkey = yield tribes.verifySignedTimestamp(bot_uuid);
if (verifiedOwnerPubkey === owner.publicKey) {
const botMember = {
botId: bot.id,
memberPubkey: sender_pub_key,
tribeUuid: chat_uuid,
msgCount: 0,
};
console.log("CREATE bot MEMBER", botMember);
yield models_1.models.BotMember.create(botMember);
}
//- need to pub back MQTT bot_install??
//- and if the pubkey=the botOwnerPubkey, confirm chatbot?
// NO - send a /guildjoin msg to BOT lib!
// and add routes to lib express with the strings for MSG_TYPE
// and here - postToBotServer /install (also do this for /uninstall)
postToBotServer(payload, bot, SphinxBot.MSG_TYPE.INSTALL);
});
}
exports.receiveBotInstall = receiveBotInstall;
// ONLY FOR BOT MAKER
function receiveBotCmd(payload) {
return __awaiter(this, void 0, void 0, function* () {
console.log("=> receiveBotCmd", payload);
const dat = payload.content || payload;
// const sender_pub_key = dat.sender.pub_key
const bot_uuid = dat.bot_uuid;
const chat_uuid = dat.chat && dat.chat.uuid;
if (!chat_uuid)
return console.log('no chat uuid');
// const amount = dat.message.amount - check price_per_use
const bot = yield models_1.models.Bot.findOne({ where: {
uuid: bot_uuid
} });
if (!bot)
return;
const botMember = yield models_1.models.BotMember.findOne({ where: {
botId: bot.id,
tribeUuid: chat_uuid,
} });
if (!botMember)
return;
botMember.update({ msgCount: (botMember || 0) + 1 });
console.log('=> post to remote BOT!!!!! bot owner');
postToBotServer(payload, bot, SphinxBot.MSG_TYPE.MESSAGE);
// forward to the entire Action back over MQTT
});
}
exports.receiveBotCmd = receiveBotCmd;
function postToBotServer(msg, bot, route) {
return __awaiter(this, void 0, void 0, function* () {
if (!bot)
return false;
if (!bot.webhook || !bot.secret)
return false;
let url = bot.webhook;
if (url.charAt(url.length - 1) === '/') {
url += route;
}
else {
url += ('/' + route);
}
const r = yield node_fetch_1.default(url, {
method: 'POST',
body: JSON.stringify(buildBotPayload(msg)),
headers: {
'x-secret': bot.secret,
'Content-Type': 'application/json'
}
});
return r.ok;
});
}
exports.postToBotServer = postToBotServer;
function buildBotPayload(msg) {
const m = {
channel: {
id: msg.chat.uuid,
send: function () { },
},
reply: function () { },
content: msg.message.content,
amount: msg.message.amount,
type: msg.type,
member: {
id: msg.sender.pub_key,
nickname: msg.sender.alias,
roles: []
}
};
if (msg.sender.role === constants.chat_roles.owner) {
if (m.member)
m.member.roles = [{
name: 'Admin'
}];
}
return m;
}
exports.buildBotPayload = buildBotPayload;
function receiveBotRes(payload) {
return __awaiter(this, void 0, void 0, function* () {
console.log("=> receiveBotRes", payload);
const dat = payload.content || payload;
if (!dat.chat || !dat.message || !dat.sender) {
return console.log('=> receiveBotRes error, no chat||msg||sender');
}
const chat_uuid = dat.chat && dat.chat.uuid;
const sender_pub_key = dat.sender.pub_key;
const amount = dat.message.amount || 0;
const msg_uuid = dat.message.uuid || '';
const content = dat.message.content;
const action = dat.action;
const bot_name = dat.bot_name;
const sender_alias = dat.sender.alias;
if (!chat_uuid)
return console.log('=> receiveBotRes Error no chat_uuid');
const chat = yield models_1.models.Chat.findOne({ where: { uuid: chat_uuid } });
if (!chat)
return console.log('=> receiveBotRes Error no chat');
const tribeOwnerPubKey = chat && chat.ownerPubkey;
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
const isTribeOwner = owner.publicKey === tribeOwnerPubKey;
if (isTribeOwner) {
console.log("=> is tribeOwner, do finalAction!");
// IF IS TRIBE ADMIN forward to the tribe
// received the entire action?
const bot_id = payload.bot_id;
actions_1.finalAction({
action, bot_name, chat_uuid, content, amount,
}, bot_id);
}
else {
const theChat = yield models_1.models.Chat.findOne({ where: {
uuid: chat_uuid
} });
if (!chat)
return console.log('=> receiveBotRes as sub error no chat');
var date = new Date();
date.setMilliseconds(0);
const sender = yield models_1.models.Contact.findOne({ where: { publicKey: sender_pub_key } });
const msg = {
chatId: chat.id,
uuid: msg_uuid,
type: constants.message_types.bot_res,
sender: (sender && sender.id) || 0,
amount: amount || 0,
date: date,
messageContent: content,
status: constants.statuses.confirmed,
createdAt: date,
updatedAt: date,
senderAlias: sender_alias || 'Bot',
};
const message = yield models_1.models.Message.create(msg);
socket.sendJson({
type: 'message',
response: jsonUtils.messageToJson(message, theChat, owner)
});
}
});
}
exports.receiveBotRes = receiveBotRes;
//# sourceMappingURL=bots.js.map