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.
281 lines
8.7 KiB
281 lines
8.7 KiB
import {models} from '../models'
|
|
import * as crypto from 'crypto'
|
|
import * as socket from '../utils/socket'
|
|
import * as helpers from '../helpers'
|
|
import * as jsonUtils from '../utils/json'
|
|
import {success, failure} from '../utils/res'
|
|
import password from '../utils/password'
|
|
import * as path from 'path'
|
|
import { Op } from 'sequelize'
|
|
|
|
const constants = require(path.join(__dirname,'../../config/constants.json'))
|
|
|
|
export const getContacts = async (req, res) => {
|
|
const contacts = await models.Contact.findAll({ where:{deleted:false}, raw: true })
|
|
const invites = await models.Invite.findAll({ raw: true })
|
|
const chats = await models.Chat.findAll({ where:{deleted:false}, raw: true })
|
|
const subscriptions = await models.Subscription.findAll({ raw: true })
|
|
const pendingMembers = await models.ChatMember.findAll({where:{
|
|
status: constants.chat_statuses.pending
|
|
}})
|
|
|
|
const contactsResponse = contacts.map(contact => {
|
|
let contactJson = jsonUtils.contactToJson(contact)
|
|
let invite = invites.find(invite => invite.contactId == contact.id)
|
|
|
|
if (invite) {
|
|
contactJson.invite = jsonUtils.inviteToJson(invite)
|
|
}
|
|
|
|
return contactJson
|
|
});
|
|
|
|
const subsResponse = subscriptions.map(s=> jsonUtils.subscriptionToJson(s,null))
|
|
const chatsResponse = chats.map(chat=> {
|
|
const theChat = chat.dataValues||chat
|
|
if(!pendingMembers) return jsonUtils.chatToJson(theChat)
|
|
const membs = pendingMembers.filter(m=>m.chatId===chat.id) || []
|
|
theChat.pendingContactIds = membs.map(m=>m.contactId)
|
|
return jsonUtils.chatToJson(theChat)
|
|
})
|
|
|
|
success(res, {
|
|
contacts: contactsResponse,
|
|
chats: chatsResponse,
|
|
subscriptions: subsResponse
|
|
})
|
|
}
|
|
|
|
export const generateToken = async (req, res) => {
|
|
console.log('=> generateToken called', { body: req.body, params: req.params, query: req.query })
|
|
|
|
const owner = await models.Contact.findOne({ where: { isOwner: true, authToken: null }})
|
|
|
|
const pwd = password
|
|
if(process.env.USE_PASSWORD==='true'){
|
|
if(pwd!==req.query.pwd) {
|
|
failure(res, 'Wrong Password')
|
|
return
|
|
} else {
|
|
console.log("PASSWORD ACCEPTED!")
|
|
}
|
|
}
|
|
|
|
if (owner) {
|
|
const hash = crypto.createHash('sha256').update(req.body['token']).digest('base64');
|
|
|
|
console.log("req.params['token']", req.params['token']);
|
|
console.log("hash", hash);
|
|
|
|
owner.update({ authToken: hash })
|
|
|
|
success(res,{})
|
|
} else {
|
|
failure(res,{})
|
|
}
|
|
}
|
|
|
|
export const updateContact = async (req, res) => {
|
|
console.log('=> updateContact called', { body: req.body, params: req.params, query: req.query })
|
|
|
|
let attrs = extractAttrs(req.body)
|
|
|
|
const contact = await models.Contact.findOne({ where: { id: req.params.id }})
|
|
if(!contact) {
|
|
return failure(res, 'no contact found')
|
|
}
|
|
|
|
// update self
|
|
const owner = await contact.update(jsonUtils.jsonToContact(attrs))
|
|
success(res, jsonUtils.contactToJson(owner))
|
|
|
|
if (!contact.isOwner) return
|
|
if (!(attrs['contact_key'] || attrs['alias'] || attrs['photo_url'])) {
|
|
return // skip if not at least one of these
|
|
}
|
|
|
|
// send updated owner info to others!
|
|
const contactIds = await models.Contact.findAll({where:{deleted:false}})
|
|
.filter(c=> c.id!==1 && c.publicKey).map(c=> c.id)
|
|
if (contactIds.length == 0) return
|
|
|
|
console.log("=> send contact_key to", contactIds)
|
|
helpers.sendContactKeys({
|
|
contactIds: contactIds,
|
|
sender: owner,
|
|
type: constants.message_types.contact_key,
|
|
})
|
|
}
|
|
|
|
export const exchangeKeys = async (req, res) => {
|
|
console.log('=> exchangeKeys called', { body: req.body, params: req.params, query: req.query })
|
|
|
|
const contact = await models.Contact.findOne({ where: { id: req.params.id }})
|
|
const owner = await models.Contact.findOne({ where: { isOwner: true }})
|
|
|
|
success(res, jsonUtils.contactToJson(contact))
|
|
|
|
helpers.sendContactKeys({
|
|
contactIds: [contact.id],
|
|
sender: owner,
|
|
type: constants.message_types.contact_key,
|
|
})
|
|
}
|
|
|
|
export const createContact = async (req, res) => {
|
|
console.log('=> createContact called', { body: req.body, params: req.params, query: req.query })
|
|
|
|
let attrs = extractAttrs(req.body)
|
|
|
|
const owner = await models.Contact.findOne({ where: { isOwner: true }})
|
|
|
|
const existing = attrs['public_key'] && await models.Contact.findOne({where:{publicKey:attrs['public_key']}})
|
|
if(existing) {
|
|
const updateObj:{[k:string]:any} = {fromGroup:false}
|
|
if(attrs['alias']) updateObj.alias = attrs['alias']
|
|
await existing.update(updateObj)
|
|
return success(res, jsonUtils.contactToJson(existing))
|
|
}
|
|
|
|
if(attrs['public_key'].length>66) attrs['public_key'] = attrs['public_key'].substring(0,66)
|
|
const createdContact = await models.Contact.create(attrs)
|
|
const contact = await createdContact.update(jsonUtils.jsonToContact(attrs))
|
|
|
|
success(res, jsonUtils.contactToJson(contact))
|
|
|
|
helpers.sendContactKeys({
|
|
contactIds: [contact.id],
|
|
sender: owner,
|
|
type: constants.message_types.contact_key,
|
|
})
|
|
}
|
|
|
|
export const deleteContact = async (req, res) => {
|
|
const id = parseInt(req.params.id||'0')
|
|
if(!id || id===1) {
|
|
failure(res, 'Cannot delete self')
|
|
return
|
|
}
|
|
|
|
const contact = await models.Contact.findOne({ where: { id } })
|
|
if(!contact) return
|
|
|
|
const owner = await models.Contact.findOne({ where: { isOwner: true }})
|
|
const tribesImAdminOf = await models.Chat.findAll({where:{ownerPubkey:owner.publicKey}})
|
|
const tribesIdArray = tribesImAdminOf && tribesImAdminOf.length && tribesImAdminOf.map(t=>t.id)
|
|
let okToDelete = true
|
|
if(tribesIdArray && tribesIdArray.length) {
|
|
const thisContactMembers = await models.ChatMember.findAll({where:{contactId:id,chatId:{[Op.in]:tribesIdArray}}})
|
|
if(thisContactMembers&&thisContactMembers.length){
|
|
// IS A MEMBER! dont delete, instead just set from_group=true
|
|
okToDelete=false
|
|
await contact.update({fromGroup:true})
|
|
}
|
|
}
|
|
|
|
if(okToDelete){
|
|
await contact.update({
|
|
deleted:true,
|
|
publicKey:'',
|
|
photoUrl:'',
|
|
alias:'Unknown',
|
|
contactKey:'',
|
|
})
|
|
}
|
|
|
|
// find and destroy chat & messages
|
|
const chats = await models.Chat.findAll({where:{deleted:false}})
|
|
chats.map(async chat => {
|
|
if (chat.type === constants.chat_types.conversation) {
|
|
const contactIds = JSON.parse(chat.contactIds)
|
|
if (contactIds.includes(id)) {
|
|
await chat.update({
|
|
deleted: true,
|
|
uuid:'',
|
|
contactIds:'[]',
|
|
name:''
|
|
})
|
|
await models.Message.destroy({ where: { chatId: chat.id } })
|
|
}
|
|
}
|
|
})
|
|
await models.Invite.destroy({ where: { contactId: id } })
|
|
await models.Subscription.destroy({ where: { contactId: id } })
|
|
|
|
success(res, {})
|
|
}
|
|
|
|
export const receiveContactKey = async (payload) => {
|
|
console.log('=> received contact key', JSON.stringify(payload))
|
|
|
|
const dat = payload.content || payload
|
|
const sender_pub_key = dat.sender.pub_key
|
|
const sender_contact_key = dat.sender.contact_key
|
|
const sender_alias = dat.sender.alias || 'Unknown'
|
|
const sender_photo_url = dat.sender.photo_url
|
|
|
|
if(!sender_pub_key) {
|
|
return console.log("no pubkey!")
|
|
}
|
|
|
|
const owner = await models.Contact.findOne({ where: { isOwner: true }})
|
|
const sender = await models.Contact.findOne({ where: { publicKey: sender_pub_key, status: constants.contact_statuses.confirmed }})
|
|
if (sender_contact_key && sender) {
|
|
const objToUpdate:{[k:string]:any} = {contactKey: sender_contact_key}
|
|
if(sender_alias) objToUpdate.alias = sender_alias
|
|
if(sender_photo_url) objToUpdate.photoUrl = sender_photo_url
|
|
await sender.update(objToUpdate)
|
|
|
|
socket.sendJson({
|
|
type: 'contact',
|
|
response: jsonUtils.contactToJson(sender)
|
|
})
|
|
} else {
|
|
console.log("DID NOT FIND SENDER")
|
|
}
|
|
|
|
helpers.sendContactKeys({
|
|
contactPubKey: sender_pub_key,
|
|
sender: owner,
|
|
type: constants.message_types.contact_key_confirmation,
|
|
})
|
|
}
|
|
|
|
export const receiveConfirmContactKey = async (payload) => {
|
|
console.log(`=> confirm contact key for ${payload.sender&&payload.sender.pub_key}`, JSON.stringify(payload))
|
|
|
|
const dat = payload.content || payload
|
|
const sender_pub_key = dat.sender.pub_key
|
|
const sender_contact_key = dat.sender.contact_key
|
|
const sender_alias = dat.sender.alias || 'Unknown'
|
|
const sender_photo_url = dat.sender.photo_url
|
|
|
|
if(!sender_pub_key) {
|
|
return console.log("no pubkey!")
|
|
}
|
|
|
|
const sender = await models.Contact.findOne({ where: { publicKey: sender_pub_key, status: constants.contact_statuses.confirmed }})
|
|
if (sender_contact_key && sender) {
|
|
const objToUpdate:{[k:string]:any} = {contactKey: sender_contact_key}
|
|
if(sender_alias) objToUpdate.alias = sender_alias
|
|
if(sender_photo_url) objToUpdate.photoUrl = sender_photo_url
|
|
await sender.update(objToUpdate)
|
|
|
|
socket.sendJson({
|
|
type: 'contact',
|
|
response: jsonUtils.contactToJson(sender)
|
|
})
|
|
}
|
|
}
|
|
|
|
const extractAttrs = body => {
|
|
let fields_to_update = ["public_key", "node_alias", "alias", "photo_url", "device_id", "status", "contact_key", "from_group", "private_photo", "notification_sound"]
|
|
let attrs = {}
|
|
Object.keys(body).forEach(key => {
|
|
if (fields_to_update.includes(key)) {
|
|
attrs[key] = body[key]
|
|
}
|
|
})
|
|
return attrs
|
|
}
|
|
|
|
|