1 // -*- mode: javascript; tab-width: 4; indent-tabs-mode: nil; -*-
2 //------------------------------------------------------------------------------
3 // This is free and unencumbered software released into the public domain.
5 // Anyone is free to copy, modify, publish, use, compile, sell, or
6 // distribute this software, either in source code form or as a compiled
7 // binary, for any purpose, commercial or non-commercial, and by any
10 // In jurisdictions that recognize copyright laws, the author or authors
11 // of this software dedicate any and all copyright interest in the
12 // software to the public domain. We make this dedication for the benefit
13 // of the public at large and to the detriment of our heirs and
14 // successors. We intend this dedication to be an overt act of
15 // relinquishment in perpetuity of all present and future rights to this
16 // software under copyright law.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 // OTHER DEALINGS IN THE SOFTWARE.
26 // For more information, please refer to <https://unlicense.org/>
27 //------------------------------------------------------------------------------
29 import * as conv from "./conversions.js"
31 // The message format version.
32 const MSG_FORMAT_VERSION = 1;
33 const MSG_FORMAT_VERSION_SIZE = 2; // Two bytes (16 bits) for the message format version.
35 export class Message {
36 constructor(time, messageId, senderTime, senderId, senderName, mimeType, body) {
37 // Plaintext fields (not serialized).
39 this.messageId = messageId;
42 this.senderTime = senderTime;
43 this.senderId = senderId;
44 this.senderName = senderName;
45 this.mimeType = mimeType;
49 static deserialize(time, messageId, binMessage) {
50 // Read and validate the message format version.
51 let formatVersion = 0;
52 for (let i = 0; i < MSG_FORMAT_VERSION_SIZE; ++i) {
53 formatVersion = formatVersion | (binMessage[i] << (i * 8));
57 let pos = MSG_FORMAT_VERSION_SIZE;
58 if (formatVersion === 1) {
59 const senderTime = conv.binToInt64(binMessage.subarray(0, 8)); pos += 8;
60 const senderId = binMessage.subarray(pos, pos + 16); pos += 16;
61 const senderName = conv.binToSenderName(binMessage.subarray(pos, pos + 16)); pos += 16;
62 const mimeType = conv.binToMimeType(binMessage.subarray(pos, pos + 4)); pos += 4;
63 const body = binMessage.subarray(pos);
64 result = new Message(time, messageId, senderTime, senderId, senderName, mimeType, body);
66 console.log(`Unsupported message format ${formatVersion}`);
73 // Encode the different (encrypted) fields as binary arrays.
74 const messageParts = [
75 conv.int64ToBin(this.senderTime),
77 conv.senderNameToBin(this.senderName),
78 conv.mimeTypeToBin(this.mimeType),
82 // Determine the size of the message.
83 let messageSize = MSG_FORMAT_VERSION_SIZE;
84 for (const part of messageParts) {
85 messageSize += part.length;
88 // Concatenate the fields into one binary array.
89 let binMessage = new Uint8Array(messageSize);
90 let pos = MSG_FORMAT_VERSION_SIZE;
91 for (const part of messageParts) {
92 binMessage.set(part, pos);
96 // Inject the message format version.
97 for (let i = 0; i < MSG_FORMAT_VERSION_SIZE; ++i) {
98 binMessage[i] = (MSG_FORMAT_VERSION >> (i * 8)) & 255;
105 return this.mimeType.startsWith("text/") ||
106 this.mimeType.startsWith("image/");