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.
479 lines
20 KiB
479 lines
20 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 models_1 = require("../models");
|
|
const jsonUtils = require("../utils/json");
|
|
const res_1 = require("../utils/res");
|
|
const network = require("../network");
|
|
const rsa = require("../crypto/rsa");
|
|
const helpers = require("../helpers");
|
|
const socket = require("../utils/socket");
|
|
const tribes = require("../utils/tribes");
|
|
const path = require("path");
|
|
const hub_1 = require("../hub");
|
|
const msg_1 = require("../utils/msg");
|
|
const sequelize_1 = require("sequelize");
|
|
const constants = require(path.join(__dirname, '../../config/constants.json'));
|
|
function joinTribe(req, res) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
console.log('=> joinTribe');
|
|
const { uuid, group_key, name, host, amount, img, owner_pubkey, owner_alias } = req.body;
|
|
const is_private = req.body.private;
|
|
const existing = yield models_1.models.Chat.findOne({ where: { uuid } });
|
|
if (existing) {
|
|
console.log('[tribes] u are already in this tribe');
|
|
return res_1.failure(res, 'cant find tribe');
|
|
}
|
|
if (!owner_pubkey || !group_key || !uuid) {
|
|
console.log('[tribes] missing required params');
|
|
return res_1.failure(res, 'missing required params');
|
|
}
|
|
const ownerPubKey = owner_pubkey;
|
|
// verify signature here?
|
|
const tribeOwner = yield models_1.models.Contact.findOne({ where: { publicKey: ownerPubKey } });
|
|
let theTribeOwner;
|
|
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
|
|
const contactIds = [owner.id];
|
|
if (tribeOwner) {
|
|
theTribeOwner = tribeOwner; // might already include??
|
|
if (!contactIds.includes(tribeOwner.id))
|
|
contactIds.push(tribeOwner.id);
|
|
}
|
|
else {
|
|
const createdContact = yield models_1.models.Contact.create({
|
|
publicKey: ownerPubKey,
|
|
contactKey: '',
|
|
alias: owner_alias || 'Unknown',
|
|
status: 1,
|
|
fromGroup: true,
|
|
});
|
|
theTribeOwner = createdContact;
|
|
contactIds.push(createdContact.id);
|
|
}
|
|
let date = new Date();
|
|
date.setMilliseconds(0);
|
|
const chatStatus = is_private ?
|
|
constants.chat_statuses.pending :
|
|
constants.chat_statuses.approved;
|
|
const chatParams = {
|
|
uuid: uuid,
|
|
contactIds: JSON.stringify(contactIds),
|
|
photoUrl: img || '',
|
|
createdAt: date,
|
|
updatedAt: date,
|
|
name: name,
|
|
type: constants.chat_types.tribe,
|
|
host: host || tribes.getHost(),
|
|
groupKey: group_key,
|
|
ownerPubkey: owner_pubkey,
|
|
private: is_private || false,
|
|
status: chatStatus,
|
|
priceToJoin: amount || 0,
|
|
};
|
|
const typeToSend = is_private ?
|
|
constants.message_types.member_request :
|
|
constants.message_types.group_join;
|
|
const contactIdsToSend = is_private ?
|
|
[theTribeOwner.id] : // ONLY SEND TO TRIBE OWNER IF ITS A REQUEST
|
|
chatParams.contactIds;
|
|
console.log('=> joinTribe: typeToSend', typeToSend);
|
|
console.log('=> joinTribe: contactIdsToSend', contactIdsToSend);
|
|
network.sendMessage({
|
|
chat: Object.assign(Object.assign({}, chatParams), { contactIds: contactIdsToSend, members: {
|
|
[owner.publicKey]: {
|
|
key: owner.contactKey,
|
|
alias: owner.alias || ''
|
|
}
|
|
} }),
|
|
amount: amount || 0,
|
|
sender: owner,
|
|
message: {},
|
|
type: typeToSend,
|
|
failure: function (e) {
|
|
res_1.failure(res, e);
|
|
},
|
|
success: function () {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const chat = yield models_1.models.Chat.create(chatParams);
|
|
models_1.models.ChatMember.create({
|
|
contactId: theTribeOwner.id,
|
|
chatId: chat.id,
|
|
role: constants.chat_roles.owner,
|
|
lastActive: date,
|
|
status: constants.chat_statuses.approved
|
|
});
|
|
res_1.success(res, jsonUtils.chatToJson(chat));
|
|
});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
exports.joinTribe = joinTribe;
|
|
function receiveMemberRequest(payload) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
console.log('=> receiveMemberRequest');
|
|
const { sender_pub_key, sender_alias, chat_uuid, chat_members, chat_type, isTribeOwner } = yield helpers.parseReceiveParams(payload);
|
|
const chat = yield models_1.models.Chat.findOne({ where: { uuid: chat_uuid } });
|
|
if (!chat)
|
|
return console.log('no chat');
|
|
const isTribe = chat_type === constants.chat_types.tribe;
|
|
if (!isTribe || !isTribeOwner)
|
|
return console.log('not a tribe');
|
|
var date = new Date();
|
|
date.setMilliseconds(0);
|
|
let theSender = null;
|
|
const member = chat_members[sender_pub_key];
|
|
const senderAlias = sender_alias || (member && member.alias) || 'Unknown';
|
|
const sender = yield models_1.models.Contact.findOne({ where: { publicKey: sender_pub_key } });
|
|
if (sender) {
|
|
theSender = sender; // might already include??
|
|
}
|
|
else {
|
|
if (member && member.key) {
|
|
const createdContact = yield models_1.models.Contact.create({
|
|
publicKey: sender_pub_key,
|
|
contactKey: member.key,
|
|
alias: senderAlias,
|
|
status: 1,
|
|
fromGroup: true,
|
|
});
|
|
theSender = createdContact;
|
|
}
|
|
}
|
|
if (!theSender)
|
|
return console.log('no sender'); // fail (no contact key?)
|
|
yield models_1.models.ChatMember.upsert({
|
|
contactId: theSender.id,
|
|
chatId: chat.id,
|
|
role: constants.chat_roles.reader,
|
|
status: constants.chat_statuses.pending,
|
|
lastActive: date,
|
|
});
|
|
const msg = {
|
|
chatId: chat.id,
|
|
type: constants.message_types.member_request,
|
|
sender: (theSender && theSender.id) || 0,
|
|
messageContent: '', remoteMessageContent: '',
|
|
status: constants.statuses.confirmed,
|
|
date: date, createdAt: date, updatedAt: date
|
|
};
|
|
if (isTribe) {
|
|
msg.senderAlias = sender_alias;
|
|
}
|
|
const message = yield models_1.models.Message.create(msg);
|
|
const theChat = yield addPendingContactIdsToChat(chat);
|
|
socket.sendJson({
|
|
type: 'member_request',
|
|
response: {
|
|
contact: jsonUtils.contactToJson(theSender || {}),
|
|
chat: jsonUtils.chatToJson(theChat),
|
|
message: jsonUtils.messageToJson(message, theChat)
|
|
}
|
|
});
|
|
});
|
|
}
|
|
exports.receiveMemberRequest = receiveMemberRequest;
|
|
function editTribe(req, res) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const { name, price_per_message, price_to_join, escrow_amount, escrow_millis, img, description, tags, unlisted, app_url, } = req.body;
|
|
const { id } = req.params;
|
|
if (!id)
|
|
return res_1.failure(res, 'group id is required');
|
|
const chat = yield models_1.models.Chat.findOne({ where: { id } });
|
|
if (!chat) {
|
|
return res_1.failure(res, 'cant find chat');
|
|
}
|
|
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
|
|
let okToUpdate = true;
|
|
if (owner.publicKey === chat.ownerPubkey) {
|
|
try {
|
|
yield tribes.edit({
|
|
uuid: chat.uuid,
|
|
name: name,
|
|
host: chat.host,
|
|
price_per_message: price_per_message || 0,
|
|
price_to_join: price_to_join || 0,
|
|
escrow_amount: escrow_amount || 0,
|
|
escrow_millis: escrow_millis || 0,
|
|
description,
|
|
tags,
|
|
img,
|
|
owner_alias: owner.alias,
|
|
unlisted,
|
|
is_private: req.body.private,
|
|
app_url,
|
|
});
|
|
}
|
|
catch (e) {
|
|
okToUpdate = false;
|
|
}
|
|
}
|
|
if (okToUpdate) {
|
|
const obj = {};
|
|
if (img)
|
|
obj.photoUrl = img;
|
|
if (name)
|
|
obj.name = name;
|
|
if (price_per_message || price_per_message === 0)
|
|
obj.pricePerMessage = price_per_message;
|
|
if (price_to_join || price_to_join === 0)
|
|
obj.priceToJoin = price_to_join;
|
|
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 (req.body.private || req.body.private === false)
|
|
obj.private = req.body.private;
|
|
if (Object.keys(obj).length > 0) {
|
|
yield chat.update(obj);
|
|
}
|
|
res_1.success(res, jsonUtils.chatToJson(chat));
|
|
}
|
|
else {
|
|
res_1.failure(res, 'failed to update tribe');
|
|
}
|
|
});
|
|
}
|
|
exports.editTribe = editTribe;
|
|
function approveOrRejectMember(req, res) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
console.log('=> approve or reject tribe member');
|
|
const msgId = parseInt(req.params['messageId']);
|
|
const contactId = parseInt(req.params['contactId']);
|
|
const status = req.params['status'];
|
|
const msg = yield models_1.models.Message.findOne({ where: { id: msgId } });
|
|
if (!msg)
|
|
return res_1.failure(res, 'no message');
|
|
const chatId = msg.chatId;
|
|
const chat = yield models_1.models.Chat.findOne({ where: { id: chatId } });
|
|
if (!chat)
|
|
return res_1.failure(res, 'no chat');
|
|
if (!msgId || !contactId || !(status === 'approved' || status === 'rejected')) {
|
|
return res_1.failure(res, 'incorrect status');
|
|
}
|
|
let memberStatus = constants.chat_statuses.rejected;
|
|
let msgType = constants.message_types.member_reject;
|
|
if (status === 'approved') {
|
|
memberStatus = constants.chat_statuses.approved;
|
|
msgType = constants.message_types.member_approve;
|
|
const contactIds = JSON.parse(chat.contactIds || '[]');
|
|
if (!contactIds.includes(contactId))
|
|
contactIds.push(contactId);
|
|
yield chat.update({ contactIds: JSON.stringify(contactIds) });
|
|
}
|
|
yield msg.update({ type: msgType });
|
|
const member = yield models_1.models.ChatMember.findOne({ where: { contactId, chatId } });
|
|
if (!member) {
|
|
return res_1.failure(res, 'cant find chat member');
|
|
}
|
|
// update ChatMember status
|
|
yield member.update({ status: memberStatus });
|
|
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
|
|
const chatToSend = chat.dataValues || chat;
|
|
network.sendMessage({
|
|
chat: Object.assign(Object.assign({}, chatToSend), { contactIds: [member.contactId] }),
|
|
amount: 0,
|
|
sender: owner,
|
|
message: {},
|
|
type: msgType,
|
|
});
|
|
const theChat = yield addPendingContactIdsToChat(chat);
|
|
res_1.success(res, {
|
|
chat: jsonUtils.chatToJson(theChat),
|
|
message: jsonUtils.messageToJson(msg, theChat)
|
|
});
|
|
});
|
|
}
|
|
exports.approveOrRejectMember = approveOrRejectMember;
|
|
function receiveMemberApprove(payload) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
console.log('=> receiveMemberApprove');
|
|
const { owner, chat, chat_name, sender } = yield helpers.parseReceiveParams(payload);
|
|
if (!chat)
|
|
return console.log('no chat');
|
|
yield chat.update({ status: constants.chat_statuses.approved });
|
|
let date = new Date();
|
|
date.setMilliseconds(0);
|
|
const msg = {
|
|
chatId: chat.id,
|
|
type: constants.message_types.member_approve,
|
|
sender: (sender && sender.id) || 0,
|
|
messageContent: '', remoteMessageContent: '',
|
|
status: constants.statuses.confirmed,
|
|
date: date, createdAt: date, updatedAt: date
|
|
};
|
|
const message = yield models_1.models.Message.create(msg);
|
|
socket.sendJson({
|
|
type: 'member_approve',
|
|
response: {
|
|
message: jsonUtils.messageToJson(message, chat),
|
|
chat: jsonUtils.chatToJson(chat),
|
|
}
|
|
});
|
|
const amount = chat.priceToJoin || 0;
|
|
const theChat = chat.dataValues || chat;
|
|
// send JOIN and my info to all
|
|
network.sendMessage({
|
|
chat: Object.assign(Object.assign({}, theChat), { members: {
|
|
[owner.publicKey]: {
|
|
key: owner.contactKey,
|
|
alias: owner.alias || ''
|
|
}
|
|
} }),
|
|
amount,
|
|
sender: owner,
|
|
message: {},
|
|
type: constants.message_types.group_join,
|
|
});
|
|
hub_1.sendNotification(chat, chat_name, 'group');
|
|
});
|
|
}
|
|
exports.receiveMemberApprove = receiveMemberApprove;
|
|
function receiveMemberReject(payload) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
console.log('=> receiveMemberReject');
|
|
const { chat, sender, chat_name } = yield helpers.parseReceiveParams(payload);
|
|
if (!chat)
|
|
return console.log('no chat');
|
|
yield chat.update({ status: constants.chat_statuses.rejected });
|
|
// dang.. nothing really to do here?
|
|
let date = new Date();
|
|
date.setMilliseconds(0);
|
|
const msg = {
|
|
chatId: chat.id,
|
|
type: constants.message_types.member_reject,
|
|
sender: (sender && sender.id) || 0,
|
|
messageContent: '', remoteMessageContent: '',
|
|
status: constants.statuses.confirmed,
|
|
date: date, createdAt: date, updatedAt: date
|
|
};
|
|
const message = yield models_1.models.Message.create(msg);
|
|
socket.sendJson({
|
|
type: 'member_reject',
|
|
response: {
|
|
message: jsonUtils.messageToJson(message, chat),
|
|
chat: jsonUtils.chatToJson(chat),
|
|
}
|
|
});
|
|
hub_1.sendNotification(chat, chat_name, 'reject');
|
|
});
|
|
}
|
|
exports.receiveMemberReject = receiveMemberReject;
|
|
function replayChatHistory(chat, contact) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
if (!(chat && chat.id && contact && contact.id)) {
|
|
return console.log('[tribes] cant replay history');
|
|
}
|
|
const msgs = yield models_1.models.Message.findAll({
|
|
where: { chatId: chat.id, type: { [sequelize_1.Op.in]: network.typesToReplay } },
|
|
order: [['id', 'desc']],
|
|
limit: 40
|
|
});
|
|
msgs.reverse();
|
|
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
|
|
asyncForEach(msgs, (m) => __awaiter(this, void 0, void 0, function* () {
|
|
if (!network.typesToReplay.includes(m.type))
|
|
return; // only for message for now
|
|
const sender = Object.assign(Object.assign({}, owner.dataValues), m.senderAlias && { alias: m.senderAlias });
|
|
let content = '';
|
|
try {
|
|
content = JSON.parse(m.remoteMessageContent);
|
|
}
|
|
catch (e) { }
|
|
const dateString = m.date && m.date.toISOString();
|
|
let mediaKeyMap;
|
|
let newMediaTerms;
|
|
if (m.type === constants.message_types.attachment) {
|
|
if (m.mediaKey && m.mediaToken) {
|
|
const muid = m.mediaToken.split('.').length && m.mediaToken.split('.')[1];
|
|
if (muid) {
|
|
const mediaKey = yield models_1.models.MediaKey.findOne({ where: {
|
|
muid, chatId: chat.id,
|
|
} });
|
|
// console.log("FOUND MEDIA KEY!!",mediaKey.dataValues)
|
|
mediaKeyMap = { chat: mediaKey.key };
|
|
newMediaTerms = { muid: mediaKey.muid };
|
|
}
|
|
}
|
|
}
|
|
let msg = network.newmsg(m.type, chat, sender, Object.assign(Object.assign(Object.assign(Object.assign({ content }, mediaKeyMap && { mediaKey: mediaKeyMap }), newMediaTerms && { mediaToken: newMediaTerms }), m.mediaType && { mediaType: m.mediaType }), dateString && { date: dateString }));
|
|
msg = yield msg_1.decryptMessage(msg, chat);
|
|
const data = yield msg_1.personalizeMessage(msg, contact, true);
|
|
const mqttTopic = `${contact.publicKey}/${chat.uuid}`;
|
|
const replayingHistory = true;
|
|
yield network.signAndSend({
|
|
data,
|
|
dest: contact.publicKey,
|
|
}, mqttTopic, replayingHistory);
|
|
}));
|
|
});
|
|
}
|
|
exports.replayChatHistory = replayChatHistory;
|
|
function createTribeChatParams(owner, contactIds, name, img, price_per_message, price_to_join, escrow_amount, escrow_millis, unlisted, is_private, app_url) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
let date = new Date();
|
|
date.setMilliseconds(0);
|
|
if (!(owner && contactIds && Array.isArray(contactIds))) {
|
|
return {};
|
|
}
|
|
// make ts sig here w LNd pubkey - that is UUID
|
|
const keys = yield rsa.genKeys();
|
|
const groupUUID = yield tribes.genSignedTimestamp();
|
|
const theContactIds = contactIds.includes(owner.id) ? contactIds : [owner.id].concat(contactIds);
|
|
return {
|
|
uuid: groupUUID,
|
|
ownerPubkey: owner.publicKey,
|
|
contactIds: JSON.stringify(theContactIds),
|
|
createdAt: date,
|
|
updatedAt: date,
|
|
photoUrl: img || '',
|
|
name: name,
|
|
type: constants.chat_types.tribe,
|
|
groupKey: keys.public,
|
|
groupPrivateKey: keys.private,
|
|
host: tribes.getHost(),
|
|
pricePerMessage: price_per_message || 0,
|
|
priceToJoin: price_to_join || 0,
|
|
escrowMillis: escrow_millis || 0,
|
|
escrowAmount: escrow_amount || 0,
|
|
unlisted: unlisted || false,
|
|
private: is_private || false,
|
|
appUrl: app_url || '',
|
|
};
|
|
});
|
|
}
|
|
exports.createTribeChatParams = createTribeChatParams;
|
|
function addPendingContactIdsToChat(achat) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const members = yield models_1.models.ChatMember.findAll({ where: {
|
|
chatId: achat.id,
|
|
status: constants.chat_statuses.pending // only pending
|
|
} });
|
|
if (!members)
|
|
return achat;
|
|
const pendingContactIds = members.map(m => m.contactId);
|
|
const chat = achat.dataValues || achat;
|
|
return Object.assign(Object.assign({}, chat), { pendingContactIds });
|
|
});
|
|
}
|
|
exports.addPendingContactIdsToChat = addPendingContactIdsToChat;
|
|
function asyncForEach(array, callback) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
for (let index = 0; index < array.length; index++) {
|
|
yield callback(array[index], index, array);
|
|
}
|
|
});
|
|
}
|
|
//# sourceMappingURL=chatTribes.js.map
|