The MumblerAPI is a AngularJS based reference API implementation for the Mumbler Initiative.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
assets
dist
examples/BasicUsage
src
.eslintrc.json
.gitignore
COC.md
COPYING.LESSER
LICENSE
README.md
gulpfile.js
package-lock.json
package.json

README.md

If your looking for the Mumbler Initiative repository head over to https://github.com/Mumbler/Mumbler.

If your looking for the source documentation of the MumblerAPI head over to https://docs.mumbler.eu.


MumblerAPI

The MumblerAPI is a AngularJS based reference API implementation for the Mumbler Initiative.

Table of contents

Requirements

This API is constructed as an AngularJS provider therefore you need AngularJS to use it within your project.

Browser

The API works basically in all modern browsers but may use a (slow) shim for cryptographic operations.

The current versions of Firefox, Chrome & Safari are supporting the native crypto interface which lead to optimal performance. You can check for your browser at https://caniuse.com/#feat=cryptography

Basic usage

The basic usage of the MumblerAPI is described in the following sub sections. All source code examples can be found within the projects MumblerAPI/examples/BasicUsage/ folder.

Upfront information

All MumblerAPI methods are constructed as Javascript Promises and can therefore be chained but more importantly run asynchronous (most likely). There is no synchronous way of interacting with the API. Especially encrypting data may be time consuming and must therefore not block the main thread.

Prerequisite

You need to add the mumblerAPI script to your JavaScript includes. You can either add the productive, minified version

<!-- Productive MumblerAPI include -->
<script src="https://cdn.mumbler.eu/api/mumbler-api.min.js"></script>

or the develop version which is identical but not minified.

<!-- Develop MumblerAPI include -->
<script src="https://cdn.mumbler.eu/api/mumbler-api.js"></script>

Do not include both. Please be also aware of the order of the includes: AngularJS must come first.

Via NPM

Of course instead of using the cdn version you can as well fetch a current copy from the npm repository

npm install @mumbler/mumbler-api

Prerequisite example

For the productive version the order should be like:

<!-- Excerpt of "MumblerAPI/examples/BasicUsage/app/index.html" -->
<!-- HEADER skipped -->
<body>

    <div ng-view></div>

    <!-- AngularJS include -->
    <script src="../node_modules/angular/angular.js"></script>
    <!-- Optional AngularJS-Route include -->
    <script src="../node_modules/angular-route/angular-route.js"></script>

    <!-- ** MumblerAPI AFTER loading AngularJS ** -->
    <script src="https://cdn.mumbler.eu/api/mumbler-api.min.js"></script>

    <!-- Your application include(s) -->
    <script src="app.js"></script>
    <script src="register/register.js"></script>
    <script src="login/login.js"></script>
    <script src="logout/logout.js"></script>
    <script src="receive/receive.js"></script>
    <script src="transmit/transmit.js"></script>
    <script src="transmit/transmit_draft.js"></script>

</body>

Angular controller

To be able to use the mumblerAPI object you need to inject it within your controller:

angular.module( 
    
    'someApp.someModule'
    
).controller(
    
    'someController',
    [
        '$scope',
        'mumblerAPI',
        function ( $scope, mumblerAPI ) {

            // use `mumblerAPI` as described below
            
        }
    ]
    
);

Register account

Register an account within the Mumbler system requires a username, a password and a security level (details below) which basically represents the encryption key length:

mumblerAPI.createAccount(
    
    'username',     // Username
    'password',     // Password
    'password',     // Same password again
    4096            // OR 2048
    
).then(
    function () {

        // Successful
    
    },
    function () {

        // Failed 
    
    }
);

Username

The username must be a string composed of standard alphanumeric characters, such as a, b, c, ..., 0, 1, 2, ... and a few special characters, such as @, $, +, ...

Further it must be at least 6 (max 32) characters long. Please note that upper case characters can be used but are internally reset to lower case characters. Therefore you can allow to enter upper-case characters as username but the following condition will hold: ABCdefGh... === abcdefgh...

All allowed characters and boundaries are summarized within the following regular expression:

^([a-z0-9\-_@.,+*$()=]{6,32}){1}$

Password

The password must be a string with at least six characters. This character set is not limited to a ASCII subset.

Please be aware: If you loose the accounts password nobody (not Mumbler infrastructure nor anybody else) can restore it and all your data linked to the account will be lost.

Security level

The security level can either be 2048 or 4096. Please consider your weakest client machine here (on which this account may be used to encrypt data). The 2048 setting may produce fast encryption rates, but the key length is only 2048 bits (and therefore "medium" secure). If all of your client browsers support the native crypto interface you can safely choose the 4096 setting. This setting will lead to a 4096 bits key length which is considered "high" security.

Limitations

Creating and operating an account is basically free of charge but limited in total account and single transmission sizes by the infrastructure:

  • Max total account size: 1GB (1024 * 1024 * 1024 Bytes)
  • Max (single) message size: 10 MB (10 * 1024 * 1024 Bytes)
  • Max (single) attachment size: 2 MB (2 * 1024 * 1024 Bytes)

Details on the limitations and how to extend them please read the Mumbler Initiative - Limitations sections on limitations.

When we have a solid way of financing the growing infrastructure we will ease the limitations. Please read Mumbler Initiative - Support for further information.

Hint: When your account size (or any other limitation) is reached, the infrastructure returns an error state if you call a method which would lead to a limit breach. You can always delete some old items to reduce the size(s).

Login

To login into an account you need your username and password:

mumblerAPI.login(

    'username',     // Username
    'password'      // Password

).then(
    function () {
    
        // Successful
    
    },
    function () {

        // Failed
    
    }
);

Logout

To logout from your account:

mumblerAPI.logout().then(
    function () {

        // Successful
    
    },
    angular.noop        // Can be an error callback handler or omitted
);

Receive

The received data is structured within folder objects. Each folder has a unique id (integer) to identify itself and query its contents. The receiving folder has the ID 0. Folder ids between 0 and 99 are reserved for future Mumbler system folders. Above that (> 99) you can register your custom folders. All message, when received are within the folder 0. For the sake of simplicity the following names are given for the top most common folders:

  • 0 -> INBOX
  • 1 -> SENT
  • 2 -> STAR
  • 3 -> DRAFT
  • 4 -> TRASH
  • 5 to 99 -> RESERVED for future use

You can reuse the names or define your own. But remember all message initially are delivered into folder id 0.

List folders

To list all folders associated with the current logged in account:

mumblerAPI.getFolders().then( 
    function ( folders ) {
        
        // Successful: The `folders` array contains a list of all folders including their properties, e.g. `id`
    
    },
    function () {

        // Failed

    }
);

The folder object is constructed as follows:

{
  "id" : 0,
  "config" : {
    "canChildren" : true,
    "virtual" : false,
    "canEmpty" : false
  },
  "name" : "INBOX"
}

The folder object can have various config properties:

  • canChildren: Signals if the folder can have child folders

  • virtual: Signals if the folder is a virtual folder which can not hold actual elements but is used as a filter for tagged messages (e.g. starred messages)

  • canEmpty: Signals if a folder can be emptied at once (e.g. "Trash" folder can be empty at once).

Open folder

When you query a folder, all containing message will be queried either from the infrastructure or the built-in cache system (if already queried earlier).

All requested subjects and properties of each requested message will be decrypted locally before being accessible. The body and attachment payload of the messages itself stay encrypted as long as you won't request a single message specifically.

In order to gather the received messages within the folder 0:

mumblerAPI.getMessageList( 0 ).then(    // can also be obtained from a single `folder` via `id` property.
    function ( messages ) {

        // Successful: The `messages` array contains a list of all messages within the selected folder

    },
    function () {
        
        // Failed
        
    }
);

If you'd like to query the results page-wise then you can query the folder with an additional parameter:

mumblerAPI.getMessageList( 0, 30 ).then(    // sets page size to 30
    function ( messages ) {

        // Successful: The `messages` array contains a list of all messages within the selected folder

    },
    function () {
        
        // Failed
        
    }
);

The second parameter sets the internal page size. The result is identical to the call without the second parameter (except for the number of array elements of course which is limited to the provided number).

In order to query the next page (or any other page):

mumblerAPI.getMessageListPage( 0, 1 ).then(    // queries the page 1 from folder 0
    function ( messages ) {

        // Successful: The `messages` array contains a list of all messages within the selected folder

    },
    function () {
        
        // Failed
        
    }
);

The first parameter again is the folder 0 and the second parameter the page you wan't to query. Please be aware of the page size is 0-based. The first page, queried by getMessageList, returns page 0.

Open message

To open a message itself which includes decryption of the message body payload:

mumblerAPI.getMessage( folder.id, message.id ).then(
    function ( message ) {

        // Successful: The `message` object contains all decrypted data (except attachment blobs) including the payload
        
    },
    function () {

        // Failed

    }
);

Open attachment

If the message contains an attachment it can be retrieved:

mumblerAPI.getAttachment(
    
    attachment      // <=  An mumbler attachment object 

).then(
    
    function ( url ) {

        // Successful: The `url` contains a ObjectURL (see https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL)

        /* Example: How to download an attachment using the ObjectURL */
        var a = document.createElement( 'a' );
        a.setAttribute( 'href', url );
        a.setAttribute( 'download', attachment.name );
        a.click();

    },
    function () {

        // Failed

    }
    
);

Mumbler message object

A message object is constructed as follows:

{
  "id" : "2eb0e820-79d5-4b76-babe-000000000000",
  
  "from" : "85a84ae6-138b-48c9-9ba7-000000000000",
  "username" : "senders_account_name",
  
  "to" : [
    { "a" : "28c2ac3f-ef7c-4353-89d1-000000000000", "u" : "recipients_account_name" },
    { "a" : "00000000-0000-0000-0000-000000000000", "u" : "second_recipients_account_name" },
    { "a" : "00000000-0000-0000-0000-000000000000", "u" : "third_recipients_account_name" },
    { "a" : "85a84ae6-138b-48c9-9ba7-000000000000", "u" : "senders_account_name" }
  ],
  
  "subject" : "Hello to you, I'm a subject",
  "body" : "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam lobortis, orci ut sollicitudin porta, ex tellus varius velit, id ultricies urna lacus vitae urna. In ac iaculis sapien, quis pulvinar mauris. Aenean lacinia magna ligula, eget fermentum est ultrices et. Praesent ut nisi id magna vehicula viverra. Fusce a euismod quam. Donec arcu velit, venenatis eu accumsan nec, fringilla cursus odio. Cras a dolor nunc. Integer sed magna vitae metus efficitur tristique a ac leo. Phasellus a pharetra elit. Vestibulum pellentesque faucibus eros, non sollicitudin erat iaculis non. Integer sit amet odio malesuada, porta diam a, laoreet diam. Suspendisse potenti. Cras ac nulla euismod, consequat massa sed, dictum turpis. Aenean eu elementum sem. Nam sem augue, gravida eget ultricies sit amet, tincidunt nec turpis. Proin magna massa, vehicula id vulputate et, fermentum sit amet ipsum. Curabitur nec nulla sit amet lectus malesuada iaculis. Integer cursus vel elit non tempor. Aliquam.",
  "attachments" : false,
  
  "folder" : 0,
  
  "sent" : 1536672208364,
  "draft" : false,
  "read" : false,
 
  "subjectDecrypted" : true,
  "decrypted" : true,
  "key" : { "0" : 152, "1" : 206, "2" : 69, "3" : 134, "4" : 159, "5" : 204, "6" : 82, "7" : 45, "8" : 237, "9" : 221, "10" : 57, "11" : 9, "12" : 178, "13" : 128, "14" : 84, "15" : 2, "16" : 175, "17" : 28, "18" : 160, "19" : 134, "20" : 8, "21" : 145, "22" : 110, "23" : 109, "24" : 212, "25" : 22, "26" : 174, "27" : 180, "28" : 253, "29" : 93, "30" : 200, "31" : 63, "32" : 15, "33" : 193, "34" : 53, "35" : 161, "36" : 204, "37" : 214, "38" : 94, "39" : 114, "40" : 73, "41" : 168, "42" : 200, "43" : 197, "44" : 22, "45" : 136, "46" : 117, "47" : 30, "48" : 225, "49" : 40, "50" : 96, "51" : 15, "52" : 61, "53" : 110, "54" : 177, "55" : 107, "56" : 126, "57" : 238, "58" : 164, "59" : 215, "60" : 84, "61" : 155, "62" : 82, "63" : 250, "64" : 91, "65" : 247, "66" : 12, "67" : 213, "68" : 121, "69" : 58, "70" : 60, "71" : 116, "72" : 232, "73" : 81, "74" : 193, "75" : 207, "76" : 2, "77" : 246, "78" : 113, "79" : 169, "80" : 240, "81" : 76, "82" : 105, "83" : 187, "84" : 153, "85" : 196, "86" : 116, "87" : 63, "88" : 219, "89" : 18, "90" : 14, "91" : 185, "92" : 27, "93" : 16, "94" : 164, "95" : 113, "96" : 75, "97" : 100, "98" : 247, "99" : 19, "100" : 108, "101" : 140, "102" : 194, "103" : 186, "104" : 79, "105" : 213, "106" : 82, "107" : 181, "108" : 68, "109" : 156, "110" : 231, "111" : 158, "112" : 194, "113" : 99, "114" : 137, "115" : 29, "116" : 77, "117" : 232, "118" : 228, "119" : 41, "120" : 18, "121" : 144, "122" : 41, "123" : 139, "124" : 190, "125" : 68, "126" : 179, "127" : 198, "128" : 120, "129" : 235, "130" : 150, "131" : 153, "132" : 16, "133" : 73, "134" : 7, "135" : 48, "136" : 195, "137" : 160, "138" : 242, "139" : 243, "140" : 64, "141" : 34, "142" : 71, "143" : 199, "144" : 111, "145" : 31, "146" : 13, "147" : 24, "148" : 243, "149" : 168, "150" : 195, "151" : 142, "152" : 70, "153" : 18, "154" : 88, "155" : 29, "156" : 223, "157" : 212, "158" : 226, "159" : 112, "160" : 135, "161" : 203, "162" : 224, "163" : 152, "164" : 0, "165" : 88, "166" : 236, "167" : 128, "168" : 39, "169" : 59, "170" : 68, "171" : 116, "172" : 167, "173" : 89, "174" : 92, "175" : 92, "176" : 112, "177" : 28, "178" : 179, "179" : 241, "180" : 230, "181" : 99, "182" : 132, "183" : 158, "184" : 51, "185" : 199, "186" : 182, "187" : 225, "188" : 189, "189" : 3, "190" : 47, "191" : 243, "192" : 156, "193" : 151, "194" : 38, "195" : 163, "196" : 129, "197" : 186, "198" : 150, "199" : 147, "200" : 20, "201" : 148, "202" : 162, "203" : 81, "204" : 98, "205" : 9, "206" : 123, "207" : 75, "208" : 79, "209" : 73, "210" : 98, "211" : 195, "212" : 6, "213" : 41, "214" : 16, "215" : 218, "216" : 61, "217" : 210, "218" : 87, "219" : 242, "220" : 186, "221" : 198, "222" : 137, "223" : 19, "224" : 68, "225" : 207, "226" : 75, "227" : 146, "228" : 134, "229" : 109, "230" : 80, "231" : 210, "232" : 154, "233" : 16, "234" : 88, "235" : 247, "236" : 250, "237" : 189, "238" : 114, "239" : 129, "240" : 151, "241" : 175, "242" : 213, "243" : 145, "244" : 120, "245" : 150, "246" : 248, "247" : 140, "248" : 189, "249" : 193, "250" : 148, "251" : 33, "252" : 20, "253" : 237, "254" : 148, "255" : 189, "256" : 133, "257" : 31, "258" : 57, "259" : 203, "260" : 250, "261" : 251, "262" : 165, "263" : 35, "264" : 255, "265" : 192, "266" : 65, "267" : 181, "268" : 175, "269" : 230, "270" : 53, "271" : 120, "272" : 87, "273" : 226, "274" : 190, "275" : 187, "276" : 191, "277" : 232, "278" : 29, "279" : 108, "280" : 163, "281" : 239, "282" : 46, "283" : 184, "284" : 20, "285" : 46, "286" : 230, "287" : 64, "288" : 82, "289" : 86, "290" : 113, "291" : 156, "292" : 14, "293" : 132, "294" : 38, "295" : 20, "296" : 176, "297" : 211, "298" : 129, "299" : 26, "300" : 59, "301" : 24, "302" : 148, "303" : 122, "304" : 88, "305" : 65, "306" : 148, "307" : 28, "308" : 174, "309" : 84, "310" : 4, "311" : 172, "312" : 161, "313" : 40, "314" : 24, "315" : 117, "316" : 161, "317" : 4, "318" : 147, "319" : 121, "320" : 210, "321" : 112, "322" : 92, "323" : 48, "324" : 46, "325" : 167, "326" : 241, "327" : 165, "328" : 94, "329" : 120, "330" : 186, "331" : 130, "332" : 30, "333" : 89, "334" : 109, "335" : 105, "336" : 31, "337" : 62, "338" : 188, "339" : 196, "340" : 197, "341" : 53, "342" : 242, "343" : 183, "344" : 135, "345" : 250, "346" : 219, "347" : 58, "348" : 53, "349" : 198, "350" : 4, "351" : 12, "352" : 8, "353" : 187, "354" : 171, "355" : 231, "356" : 71, "357" : 89, "358" : 178, "359" : 134, "360" : 78, "361" : 149, "362" : 162, "363" : 24, "364" : 202, "365" : 170, "366" : 47, "367" : 33, "368" : 121, "369" : 140, "370" : 227, "371" : 234, "372" : 170, "373" : 26, "374" : 158, "375" : 212, "376" : 31, "377" : 220, "378" : 206, "379" : 121, "380" : 136, "381" : 107, "382" : 143, "383" : 201, "384" : 54, "385" : 139, "386" : 3, "387" : 222, "388" : 58, "389" : 164, "390" : 207, "391" : 136, "392" : 146, "393" : 187, "394" : 72, "395" : 100, "396" : 180, "397" : 80, "398" : 153, "399" : 188, "400" : 188, "401" : 254, "402" : 58, "403" : 115, "404" : 96, "405" : 75, "406" : 183, "407" : 27, "408" : 107, "409" : 1, "410" : 108, "411" : 61, "412" : 144, "413" : 68, "414" : 69, "415" : 215, "416" : 70, "417" : 239, "418" : 216, "419" : 86, "420" : 52, "421" : 199, "422" : 59, "423" : 161, "424" : 25, "425" : 240, "426" : 14, "427" : 96, "428" : 240, "429" : 202, "430" : 36, "431" : 82, "432" : 93, "433" : 81, "434" : 46, "435" : 130, "436" : 168, "437" : 56, "438" : 127, "439" : 26, "440" : 41, "441" : 198, "442" : 46, "443" : 39, "444" : 161, "445" : 20, "446" : 230, "447" : 29, "448" : 80, "449" : 208, "450" : 216, "451" : 255, "452" : 95, "453" : 112, "454" : 116, "455" : 101, "456" : 229, "457" : 65, "458" : 227, "459" : 112, "460" : 161, "461" : 203, "462" : 60, "463" : 162, "464" : 245, "465" : 207, "466" : 171, "467" : 113, "468" : 97, "469" : 48, "470" : 72, "471" : 213, "472" : 66, "473" : 122, "474" : 238, "475" : 97, "476" : 132, "477" : 205, "478" : 223, "479" : 186, "480" : 35, "481" : 144, "482" : 20, "483" : 68, "484" : 156, "485" : 225, "486" : 91, "487" : 119, "488" : 131, "489" : 166, "490" : 25, "491" : 117, "492" : 176, "493" : 71, "494" : 248, "495" : 120, "496" : 86, "497" : 140, "498" : 228, "499" : 205, "500" : 106, "501" : 168, "502" : 34, "503" : 157, "504" : 39, "505" : 16, "506" : 132, "507" : 234, "508" : 121, "509" : 115, "510" : 229, "511" : 158 }
}

Although the message object is pretty self explanatory a few hints are still in order (I think):

  • from and username: Senders account id and username (identical to last element within to)

  • to: The arrays last element is always the sender with its mumbler account id (e.g. "a" : "85a84ae6-138b-48c9-9ba7-000000000000") and its mumbler account name (e.g. "u" : "senders_account_name"). All other accounts are recipients. Your account may not be the first within the array, but must be a part of the array (otherwise you would not received it at all :-))

  • draft: If a message is flagged as a draft ("draft" : true) it may not contain all fields. For example a draft may not have any recipients (to) yet. For creating drafts please read below.

  • attachments: Is either false or an array of attachment objects. Please read below for attachment handling.

  • subjectDecrypted: Signals if the subject was decrypted already. This should be set to true in normal operation (after receiving via a folders content).

  • decrypted: Signals if the body payload is still decrypted ("decrypted" : true) or not ("decrypted" : false). For example, when you receive a message list via getMessageList the body is still decrypted until you call getMessage explicitly.

  • key: An Ascii representation of the synchronous session key used for this message (please see Mumbler Initiative for information on the cryptographic details).

Transmit

To transmit (send) a mumbler message you can either construct it as a complete message or as a draft message.

Recipient

Regardless which message transmission type you choose you need to gather the recipient(s) object
(which includes the recipients public crypto key to use):

mumblerAPI.getPublicKeyInformation( 'recipient_name' ).then(
    function ( recipient ) {
    
         // Successful: The `recipient` object contains the necessary information
    
    },
    function () {
    
         // Failed
    }
);

If you like to send to multiple recipients you need to call the getPublicKeyInformation subsequently.

Complete message

When constructed as complete message it needs to be fully populated with recipient(s), subject, body and optional attachment(s) before actually transmitting them to the infrastructure.

To transmit a simple complete message:

mumblerAPI.transmitMessage( 
    {

        header  : { 
            recipients : [          // <= List of recipients objects
                recipient           // <= Single recipient object queried via `getPublicKeyInformation`
            ]
        },
        subject     : 'subject',    // <= Message subject
        body        : 'body',       // <= Message body payload
        attachments : []            // <= Message attachment payload
    
    } 
).then(
   function () {
   
        // Successful
   
   },
   function () {
   
        // Failed
   }
);

The complete message object is encrypted and sent over to the infrastructure where it will be delivered into the recipient(s) account.

Hint: Depending on the total size of the message the API may cut the message into multiple blobs and transmit them subsequently. Therefore you may see multiple HTTP requests sent to the infrastructure for one single message. Especially for huge payload bodies or attachments this is most certainly the case.

Draft message

When constructed as draft message it doesn't require the message to be fully populate at once. On the contrary the message will be constructed with single elements one-by-one. The already constructed parts are stored (encrypted) within the accounts draft folder (id 3) on the infrastructure and can be amended in the future before actually transmitting them.

Start draft message
mumblerAPI.newMessageDraft().then(
    function ( messageId ) {

        // Successful: The `messageId` is required for all subsequent operations

    },
    function () {

        // Failed

    }

);

Hint: When obtained a messageId the message can be constructed in any order.

Add body payload

Add a body payload to the draft message:

mumblerAPI.setDraftBody( 
    
    messageId,      // <= The messageId queried via `newMessageDraft`
    'BODY'          // <= The message body (can be anything "string-able")
     
).then(
    function () {

        // Successful

    },
    function () {

        // Failed

    }
    
);

Note: The body payload will be encrypted before uploading to the infrastructure.

Add attachment

Add an single attachment to the draft message:

mumblerAPI.addAttachment( 
    
    messageId,      // <= The messageId queried via `newMessageDraft`
    attachment      // <= The mumbler attachment object (must be created via `createAttachment`)

).then(
     function () {
 
         // Successful
 
     },
     function () {
 
         // Failed
 
     }
     
 );

Note: The attachment payload will be encrypted before uploading to the infrastructure.

Add recipient(s)

This should only be done for convenience purposes (see hint)

Add the recipient(s) to the draft message.

mumblerAPI.setDraftRecipients(
    
    messageId,          // <= The messageId queried via `newMessageDraft`
    [
        recipient1,     // <= Recipient 1 queried via `getPublicKeyInformation`
        recipient2      // <= (optional) Recipient 2 queried via `getPublicKeyInformation` and so on
    ]
    
).then(
    function () {
    
        // Successful
    
    },
    function () {
    
        // Failed
    
    }

);

Hint: This method only stores recipient objects within the message.

Add subject

This should only be done for convenience purposes (see hint)

Add a subject to the draft message:

mumblerAPI.setDraftSubject(
    
    messageId,      // <= The messageId queried via `newMessageDraft`
    'SUBJECT'       // <= The message subject
    
).then(     
    function ( success ) {

        // Successful

    },
    function () {

        // Failed

    }

);

Hint: Due to the fact that at this time it isn't safeguarded that a recipient list with keys is present. Therefore the subject will be encrypted with the current sessions' key and is not readable by any recipients (if they were present in the message at this time).

Transmit

You can transmit a message at any time. To transmit a draft message:

mumblerAPI.transmitDraftMessage(
    
    messageId,          // <= The messageId queried via `newMessageDraft`
    [
        recipient1,     // <= Recipient 1 queried via `getPublicKeyInformation`
        recipient2      // <= (optional) Recipient 2 queried via `getPublicKeyInformation` and so on
    ],
    'subject'           // <= The subject of the message
      
).then(
    
    function () {

        // Successful

    },
    function () {

        // Failed

    }
    
);

Note: You need the recipients list and the subject to call this method regardless on previous calls to setDraftSubject and/or setDraftRecipients. The encryption of the subject with the keys of the recipients can only be safeguarded at this point.

Attachment

Regardless which message transmission type you choose a attachment always needs to be encapsulated into an mumbler attachment object.

A mumbler attachment object can be constructed:

mumblerAPI.createAttachment( 
    
    file        // <= DOM File, e.g. from <input type="file" ...> (see https://www.w3.org/TR/FileAPI/#file-section for specification)
    
).then(
  
    function ( attachment ) {

        // Successful: `attachment` is a fully populated mumbler attachment object

    },
    function () {

        // Failed

    }
  
);

The file parameter can be either from an actual <input type="file" ...> DOM element or can be constructed programmatically. There are many possible ways with the identical outcome (e.g. Fetch-API).

A common and browser robust AngularJS way is to create a input element programmatically, like:

function chooseFileDialog ( multiple, accepted ) {

    var defer = $q.defer();

    var dialog = document.createElement( 'input' );
    dialog.type = 'file';

    if ( multiple === true ) {

        dialog.multiple = multiple;
    
    }

    if ( angular.isArray( accepted ) ) {

        dialog.accept = accepted.join( ',' );
    
    }
    else if ( angular.isString( accepted ) ) {

        dialog.accept = accepted;
    
    }

    dialog.addEventListener(
        'change',
        function () {

            if ( typeof this.files === 'object' && null !== this.files )
            {

                defer.resolve( this.files );
            
            }
            else
            {

                defer.reject( this );
            
            }
        
        }
    );

    dialog.click();

    return defer.promise;

}

Hint: To use this method your controller needs to inject the $q object.

Hint 2: Please be aware, that the promise resolves with an array of files. The createAttachment only takes one file at a time.

Attachment for draft message

When constructing a draft message type, the createAttachment can be used to directly create the mumbler attachment object and add it to the draft message in one call.

Simply add the messageId as second parameter:

mumblerAPI.createAttachment( 
    
    file,           // <= DOM File, e.g. from <input type="file" ...> (see https://www.w3.org/TR/FileAPI/#file-section for specification)
    messageId       // <= The messageId queried via `newMessageDraft`
    
).then(
  
    function ( attachment ) {

        // Successful: `attachment` is a fully populated mumbler attachment object

    },
    function () {

        // Failed

    }
  
);

Documentation

The latest source documentation can be found here https://docs.mumbler.eu

Development / Contributing

If you like to contribute in the further development of the AngularJS MumblerAPI you can clone this repository via

git clone https://www.github.com/magnusit/mumblerapi MumblerAPI

Pull request

Feel free to engage in the further development, but be aware, that we're screening changes within the cryptographic part of the API very closely and need a good documentation on your changes before we consider a merge into the master branch. This part is essential for the Mumbler Initiative and will not easy be subject of changes.

Besides that:

--- Pull request are more then welcome ---

PR documentation

Please comment your changes extensively. This way we can speed up the merge into the master branch. Uncommented pull requests will not be merged.

PR Linting

Please lint your source code changes according to the enclosed .eslintrc.json. You will see, that we're very eager about the whitespaces and padded blocks. We strongly believe this is the best way to read complex long promise-chains and blocks scopes more efficiently. Un-linted files will not be merged.

Code of conduct

Lust but not least please read the COC.md file for details on our code of conduct. Contributing to the Mumbler Initiative you agree to our code of conduct.

Built With

Testing

We initially used the karma framework to test early version of the library, but we're decided very quickly that testing the outcome of encrypted blobs is highly difficult and mostly impossible (e.g. use of SALT). We added some basic tests but abandoned the test writing soon after that. This is the reason why the test folder was added to the .gitignore (pretty messy within there). If you still like to engage in karma-testing, let us now. We can send you a copy of the current test specs.

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

Authors

License

This project is licensed under the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3 (LGPL-3.0). Please see LICENSE and COPYING.LESSER files for details.