Wire doesn't support exporting chat history (wireapp/wire#116). It is, however, possible to access the decrypted messages in the local storage of a browser. This guide will help you produce a text export once you are logged in https://app.wire.com. All from the browser console.
Open a connection to your browser local storage:
var db
var request = indexedDB.open("wire@production@4278eafb-b21c-4d7a-aad4-2be4fa3a9fa0@permanent")
request.onerror = function(event) {
console.log("Why didn't you allow my web app to use IndexedDB?!")
}
request.onsuccess = function(event) {
db = event.target.result
}
Fetch all conversation:
var conversations = []
var objectStore = db.transaction("conversations").objectStore("conversations")
objectStore.getAll().onsuccess = function(event) {
conversations = event.target.result
}
List their name alongside their ID:
conversations.forEach((value, index, array) => console.log(value.id, value.name))
Once you find the conversation, store its ID:
var conversation_id = "..."
Fetch all its messages:
var messages = []
var objectStore = db.transaction("events").objectStore("events")
var index = objectStore.index("conversation")
var singleKeyRange = IDBKeyRange.only(conversation_id)
index.openCursor(singleKeyRange).onsuccess = function(event) {
var cursor = event.target.result
if (cursor) {
messages.push(cursor.value)
cursor.continue()
}
}
Find all user IDs in those messages:
var user_ids = new Set()
messages.forEach((x) => user_ids.add(x.from))
Usernames need to be queried to the server as they are not kept in local storage, so request first an access token:
var token = ''
fetch("https://prod-nginz-https.wire.com/access", {
"headers": {
"accept": "application/json, text/plain, */*",
"accept-language": "en-US,en;q=0.9",
},
"method": "POST",
"credentials": "include"
}).then(response => response.json()).then(data => token = data.access_token);
And build a map of user IDs to usernames from a server request:
var usernames = {}
fetch(`https://prod-nginz-https.wire.com/users?ids=${Array.from(user_ids).join()}`, {
"headers": {
"accept": "application/json, text/plain, */*",
"authorization": `Bearer ${token}`,
},
"method": "GET",
}).then(response => response.json()).then(data => {
data.forEach(item => usernames[item.id] = item.name)
})
Finally, define helper functions render the messages:
var getUsernames = (user_ids) => user_ids.map(id => usernames[id])
var renderHeader = (message, idx, debug) => {
var header = `${getUsernames([message.from])} ${message.time}`
var debug_info = `[#${idx} ${message.type}]`
return !debug ? `${header}:` : `${header} ${debug_info}:`
}
var exportHistory = (messages, debug) => {
var history_export = ''
messages.every((m, idx) => {
if (m.type == 'conversation.group-creation') {
users = getUsernames(m.data.userIds)
return `
${renderHeader(m, idx, debug)}
-->> started the conversation **${m.data.name}** <<--
-->> with ${users.join(', ')}<<--
`
} if (m.type == 'conversation.rename'
&& m.data.name !== undefined) {
entry = `
${renderHeader(m, idx, debug)}
-->> renamed the conversation **${m.data.name}**<<--
`
} else if (m.type == 'conversation.member-join') {
users = getUsernames(m.data.user_ids)
entry = `
${renderHeader(m, idx, debug)}
-->> added ${users.join(', ')} to the conversation <<--
`
} else if (m.type == 'conversation.member-leave') {
users = getUsernames(m.data.user_ids)
entry = `
${renderHeader(m, idx, debug)}
-->> removed ${users.join(', ')} <<--
`
} else if (m.type == 'conversation.message-timer-update') {
entry = `
${renderHeader(m, idx, debug)}
-->> set the message timer to ${m.data.message_timer}ms <<--
`
} else if (m.type == 'conversation.asset-add') {
entry = `
${renderHeader(m, idx, debug)}
-->> uploaded ${m.data.content_type} <<--
`
} else if (m.type == 'conversation.location') {
entry = `
${renderHeader(m, idx, debug)}
-->> shared location <<--
-->> ${m.data.location.name} (${m.data.location.latitude}, ${m.data.location.latitude}) <<--
`
} else if (m.type == 'conversation.voice-channel-deactivate') {
entry = `
${renderHeader(m, idx, debug)}
-->> called <<--
`
} else if (m.type == 'conversation.delete-everywhere') {
entry = `
${renderHeader(m, idx, debug)}
-->> deleted message <<--
`
} else if (m.type == 'conversation.knock') {
entry = `
${renderHeader(m, idx, debug)}
-->> pinged <<--
`
} else if (m.type == 'conversation.message-add') {
entry = `
${renderHeader(m, idx, debug)}
${m.data.content}
`
} else if (m.type == 'conversation.missed-messages'
|| m.type == 'conversation.voice-channel-activate') {
return true
} else {
debugger
}
if (m.time.slice(0, 4) == '1970') {
history_export = entry + history_export
} else {
history_export += entry
}
return true
})
return history_export.trim()
}
And just print the whole history to the console:
console.log(exportHistory(messages, debug=false))
NOTE: This was tested on Brave browser.
Todo:
- Find message reply information
- Display likes