wickrio-bot-api
Version:
The official Wickr IO Bot API Framework
545 lines (488 loc) • 12.9 kB
JavaScript
const fs = require('fs')
const WickrUser = require('../WickrUser')
let encryptor
const encryptorDefined = false
const util = require('util')
class MessageService {
constructor({
rawMessage,
admins,
adminOnly,
wickrUsers,
wickrAPI,
adminDMonly = false,
testOnly = false,
}) {
this.rawMessage = rawMessage
this.adminDMonly = adminDMonly
this.myAdmins = admins
this.adminOnly = adminOnly
this.wickrUsers = wickrUsers
this.wickrAPI = wickrAPI
this.user = null
this.testOnly = testOnly
const {
time,
messageID,
users,
ttl,
bor,
control,
msgTS,
receiver,
file,
filename,
message,
command,
argument,
vGroupID,
convoType,
msgType,
userEmail,
isAdmin,
latitude,
longitude,
isVoiceMemo,
voiceMemoDuration,
} = this.parseRawMsg({ rawMessage: this.rawMessage })
// OG MSG DATA
this.time = time || null
this.botName = JSON.parse(process.env.tokens).WICKRIO_BOT_NAME.value || null
this.messageID = messageID || null
this.users = users || null
this.ttl = ttl || null
this.bor = bor || false
this.control = control || null
this.msgTS = msgTS || null
this.receiver = receiver || null
this.filepath = file || null
this.file = file ? fs.readFileSync(file) : null
this.filename = filename || null
this.message = message || null
this.command = command ? command.toLowerCase().trim() : null
this.argument = argument ? argument.toLowerCase().trim() : null
this.vGroupID = vGroupID
this.convoType = convoType
this.msgType = msgType
this.userEmail = userEmail
this.isAdmin = isAdmin || false
this.latitude = latitude || null
this.longitude = longitude || null
this.location =
latitude || longitude
? 'http://www.google.com/maps/place/' +
this.latitude +
',' +
this.longitude
: ''
this.isVoiceMemo = isVoiceMemo || false
this.voiceMemoDuration = voiceMemoDuration || null
// let personalVGroupID = ''
// if (convoType === 'personal') personalVGroupID = vGroupID
// create a directory for the user using their email as the name
// Check if a user exists in the database
this.user = this.getOrCreateUser({ userEmail }) // Look up user by their wickr email
}
getMessageData() {
return {
time: this.time,
botName: this.botName,
messageID: this.messageID,
users: this.users,
ttl: this.ttl,
bor: this.bor,
control: this.control,
msgTS: this.msgTS,
receiver: this.receiver,
filepath: this.filepath,
file: this.file,
filename: this.filename,
message: this.message,
command: this.command,
argument: this.argument,
vGroupID: this.vGroupID,
convoType: this.convoType,
msgType: this.msgType,
user: this.user,
userEmail: this.userEmail,
isAdmin: this.isAdmin,
latitude: this.latitude,
longitude: this.longitude,
location: this.location,
isVoiceMemo: this.isVoiceMemo,
voiceMemoDuration: this.voiceMemoDuration,
}
}
parseRawMsg({ rawMessage }) {
const jsonmsg = JSON.parse(rawMessage)
const {
message_id: messageID,
message,
edit,
control,
file,
msg_ts: msgTS,
time,
receiver,
sender: userEmail,
ttl,
location,
vgroupid: vGroupID,
msgtype: rawMsgType,
call,
users,
keyverify,
} = jsonmsg
let { bor } = jsonmsg
if (!bor) bor = 0
// const msgtype = message.msgtype
// const vGroupID = message.vgroupid
let convoType = null
let command = null
let argument = null
// This doesn't capture @ mentions
if (message) {
const parsedData = message.trim().match(/^(\/[a-zA-Z]+)([\s\S]*)$/)
if (parsedData !== null) {
command = parsedData[1]
if (parsedData[2] !== '') {
argument = parsedData[2]
.trim()
.replace(/^@[^ ]+ /, '')
.trim()
}
}
}
// Get the admin, if this is an admin user
const localWickrAdmins = this.myAdmins
let admin
if (localWickrAdmins) {
admin = localWickrAdmins.getAdmin(userEmail)
}
// If ONLY admins can receive and handle messages and this is
// not an admin, then drop the message
if (this.adminOnly === true && admin === undefined) {
console.log('Dropping message from non-admin user!')
return {}
}
// Set the isAdmin flag
const isAdmin = admin !== undefined
// Determine the convo type (1to1, group, or room)
if (vGroupID.charAt(0) === 'S') convoType = 'room'
else if (vGroupID.charAt(0) === 'G') convoType = 'groupconvo'
else convoType = 'personal'
let parsedMessage = {
messageID,
message,
msgTS,
time,
receiver,
users,
vGroupID,
user: this.user,
userEmail,
convoType,
isAdmin,
ttl,
bor,
}
if (rawMsgType === 6000) {
// file transfer msgtype
if (file.isvoicememo) {
parsedMessage = {
...parsedMessage,
file: file.localfilename,
filename: file.filename,
isVoiceMemo: true,
voiceMemoDuration: file.voicememoduration,
msgType: 'file',
}
return parsedMessage
} else {
parsedMessage = {
...parsedMessage,
file: file.localfilename,
filename: file.filename,
isVoiceMemo: false,
msgType: 'file',
}
}
return parsedMessage
} else if (rawMsgType === 8000) {
// location msgtype
parsedMessage = {
...parsedMessage,
latitude: location.latitude,
longitude: location.longitude,
msgType: 'location',
}
return parsedMessage
} else if (call) {
parsedMessage = {
...parsedMessage,
status: call.status,
call,
msgType: 'call',
}
return parsedMessage
} else if (rawMsgType === 3000) {
// verification msgtype
parsedMessage = {
...parsedMessage,
control,
msgType: 'keyverify',
}
return parsedMessage
} else if (rawMsgType >= 4000 && rawMsgType <= 5000) {
// control messages
parsedMessage = {
...parsedMessage,
control,
msgType: 'control',
}
return parsedMessage
} else if (rawMsgType === 9000) {
// edit message
parsedMessage = {
...parsedMessage,
msgType: 'edit',
}
return parsedMessage
} else if (message === undefined) {
return {}
}
// If this is an admin then process any admin commands
// if adminDMonly is false
if (isAdmin) {
if (!this.adminDMonly || convoType === 'personal') {
if (
localWickrAdmins.processAdminCommand(
userEmail,
vGroupID,
command,
argument
)
) {
// If this admin command was processed then return the msgtype as 'admin'
parsedMessage = {
...parsedMessage,
msgType: 'admin',
}
return parsedMessage
}
}
}
parsedMessage = {
...parsedMessage,
command,
argument,
}
return parsedMessage
}
// TODO why use getters and setters here??
getAdminList() {
return this.myAdmins
}
getMessage() {
return this.message
}
// handle history stuff
getDates() {
const fromDate = this.fromDate
const toDate = this.toDate
return { fromDate, toDate }
}
// A getter for the argument to a command
// The argument is the message minus the /command
getArgument() {
return this.argument
}
// A getter for the isAdmin field returns true if the current user
// has admin privilliges
getIsAdmin() {
return this.isAdmin
}
getUserEmail() {
return this.userEmail
}
getVGroupID() {
return this.vGroupID
}
getCommand() {
return this.command
}
getUserCurrentStateConstructor() {
return this.user.currentState
}
getUserCurrentCmdInfoConstructor() {
return this.user.currentCmdInfo
}
getFile() {
return this.file
}
getFilePath() {
return this.filepath
}
getFilename() {
return this.filename
}
getUser() {
return this.user
}
affirmativeReply() {
return (
this.message.toLowerCase() === 'yes' || this.message.toLowerCase() === 'y'
)
}
negativeReply() {
return (
this.message.toLowerCase() === 'no' || this.message.toLowerCase() === 'n'
)
}
isInt() {
if (!Number.isInteger(+this.message)) {
return false
}
return true
}
/*
* User functions
*/
addUserToDB(wickrUser) {
this.wickrUsers.push(wickrUser)
this.saveData()
this.user = wickrUser
console.log('New Wickr user added to database.')
return wickrUser
}
setUserCurrentState({ currentState }) {
let userWithState
// this.wickrUsers.find(user => {
// return user.userEmail === this.userEmail
// })
this.wickrUsers = this.wickrUsers.map(user => {
userWithState = {
...user,
currentState,
}
this.user = userWithState
if (user.userEmail === this.userEmail) return userWithState
else return user
})
this.saveData()
console.log('Wickr state added to db.')
return userWithState
}
getUserCurrentState({ userEmail }) {
const userInDB = this.getUserFromDB({ userEmail })
return userInDB.currentState
}
matchUserCommandCurrentState({ commandState }) {
const { userEmail } = this
const userCurrentState = this.getUserCurrentState({
userEmail,
})
return userCurrentState === commandState
}
setUserCurrentCmdInfo({ currentCmdInfo }) {
let userWithState
this.wickrUsers = this.wickrUsers.map(user => {
userWithState = {
...user,
currentCmdInfo,
}
this.user = userWithState
if (user.userEmail === this.userEmail) return userWithState
else return user
})
this.saveData()
console.log('Wickr cmdInfo added to db.')
return userWithState
}
getUserCurrentCmdInfo() {
const { userEmail } = this
const userInDB = this.getUserFromDB({ userEmail })
return userInDB.currentCmdInfo
}
getOrCreateUser({ userEmail }) {
// on every every message,
// see if there is a submission in the bot for the user,
// if there is, return user
// if not,
// get message,
// userEmail
// vGroupID,
// personalVGroupID, // what personalvGroupID
// command,
// argument from current message
// and add the use to to db and return the user
const {
message,
vGroupID,
personalVGroupID, // what personalvGroupID
command,
argument,
} = this
let user = this.getUserFromDB({ userEmail }) // Look up user by their wickr email
if (user === undefined) {
console.log('creating new user')
const wickrUser = new WickrUser(userEmail, {
message,
vGroupID,
personalVGroupID, // what personalvGroupID
command,
argument,
currentState: null, // undefined
currentCmdInfo: null, // undefined
})
user = this.addUserToDB(wickrUser) // Add a new user to the database
}
return user
}
getUserFromDB({ userEmail }) {
const found = this.wickrUsers.find(function (user) {
return user.userEmail === userEmail
})
return found
}
getUsersFromDB() {
return this.wickrUsers
}
deleteUserFromDB(userEmail) {
const found = this.wickrUsers.find(function (user) {
return user.userEmail === userEmail
})
const index = this.wickrUsers.indexOf(found)
this.wickrUsers.splice(index, 1)
return found
}
async saveData() {
try {
// If this is a test then do not save data
if (this.testOnly) {
console.log('saveData: test, not saving!')
return
}
console.log('Encrypting user database...')
// console.log({ storingTheseUsers: this.wickrUsers })
if (this.wickrUsers.length === 0) {
return
}
let serialusers
if (encryptorDefined === true) {
// Encrypt
serialusers = encryptor.encrypt(this.wickrUsers)
} else {
serialusers = JSON.stringify(this.wickrUsers)
}
const encrypted = await this.wickrAPI.cmdEncryptString(serialusers)
fs.writeFileSync('users.txt', encrypted, 'utf-8')
console.log('User database saved to file!')
return true
} catch (err) {
console.log(err)
return false
}
}
}
module.exports = MessageService