Socket
Socket
Sign inDemoInstall

apple-icloud

Package Overview
Dependencies
124
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.0 to 1.0.2

demo/contacts/changeGroups.js

2

demo/findme/findMe.js

@@ -14,3 +14,3 @@ // Require function that already logs in and asks for the credentials if needed

}
//console.log(devices);
console.log(devices);
})();

@@ -8,3 +8,3 @@ // Require function that already logs in and asks for the credentials if needed

var locations = await myCloud.Friends.getLocations();
const locations = await myCloud.Friends.getLocations();

@@ -11,0 +11,0 @@ console.log(locations);

@@ -87,48 +87,4 @@ /*

/*console.log("\nPlease log in with your credentials! (Username = Mail)");
console.log("Will save your session at '" + sessionPath + "'\n");
prompt.get({
properties: {
username: {
pattern: /^.*$/,
message: 'Mail',
required: false
},
password: {
required: false,
hidden: true
}
}
}, function(err, input) {
if (err) return console.error(err);
// This creates your iCloud instance
var myCloud = new iCloud(sessionPath, input.username, input.password);
myCloud.on("ready", async function() {
if (myCloud.twoFactorAuthenticationIsRequired) {
prompt.get(["Security Code"], function(err, input) {
if (err) return console.error(err);
const code = input["Security Code"];
myCloud.securityCode = code;
});
}
else {
console.log("You are logged in successfully!");
console.log("Get contact data...");
//var contactsData = await myCloud.Contacts.list();
//console.log(contactsData);
resolve(myCloud);
}
});
myCloud.on("sessionUpdate", function() {
myCloud.saveSession();
});
});*/
});
}

@@ -13,4 +13,7 @@ // Require function that already logs in and asks for the credentials if needed

console.log(notification);
// demonstrate deactivating push after one notification
myCloud.deactivatePush();
});
})();
const EventEmitter = require('events');
const fs = require('fs');
const { getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, fillMethods } = require("./resources/helper");
const { getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, fillMethods, fillDefaults} = require("./resources/helper");

@@ -14,2 +14,4 @@ Array.prototype.indexOfKey = indexOfKey;

self.loggedIn = false;
// enable push initially
self.enablePush = true;
// If the session argument is a string, it will be interpreted as a file path and the file will be read

@@ -45,3 +47,3 @@ if (typeof session === "string") {

// Session Validation. This adds default properties to the session that doesn't exists
session = session.fillDefaults({
session = fillDefaults(session, {
username: username,

@@ -101,3 +103,3 @@ password: password,

// Session object is validated. Now, the (self) instance will be extended with session's properties using the fill defaults function.
self = self.fillDefaults(session);
self = fillDefaults(self, session);

@@ -116,9 +118,17 @@ Object.keys(self.apps).forEach(function(appPropName) {

//console.log(self.auth.cookies.length > 0, !!self.auth.token, self.account != {}, self.username === username);
return (self.auth.cookies.length > 0 && self.auth.token && self.account != {} && self.username === username);
return (self.auth.cookies.length > 0 && self.auth.token && self.account != {} && username ? (self.username === username) : true);
})();
self.cookiesValid = (function() {
const timestamp = new Date().getTime();
// Get list of cookies, represented to a boolean value wether the cookie is expired or no
const cookiesExpired = self.auth.cookies.map(cookie => new Date(cookie.Expires).getTime() - timestamp < 0);
// ignore cookie wich is expiring in 1970 --> so no extra code auth, when starting app
const cookiesExpired = self.auth.cookies.map(function (cookie) {
if ('X-APPLE-WEBAUTH-HSA-LOGIN' in cookie && 'Expires' in cookie) {
return false;
} else {
return new Date(cookie.Expires).getTime() - timestamp < 0;
}
});
// If no cookie is expired, the array contains just 'false' keys

@@ -278,3 +288,9 @@ // Return wether there is no expired cookie (true)

}
initPush(callback = function() {}) {
initPush(callback = function () { }) {
// breaks the callback loop if we decide to disable push
if (!this.enablePush) {
this.enablePush = true;
return;
}
var self = this;

@@ -302,3 +318,3 @@ self.Setup.registerTopics(self, function(err, result) {

});
return self.Setup.getPushToken(self.push.topics, self.push.ttl, self.account.dsInfo.dsid, cookiesToStr(self.auth.cookies), self.clientId, function(err, token, url, cookies) {
return self.Setup.getPushToken(self, cookiesToStr(self.auth.cookies), function(err, token, url, cookies) {
if (err) return callback(err);

@@ -321,2 +337,7 @@ // Got push token.

}
deactivatePush() {
this.enablePush = false;
}
exportSession() {

@@ -340,3 +361,3 @@ // Export session as object

if (file) {
fs.writeFile(file, JSON.stringify(this.exportSession(), null, 2), function(err) {
fs.writeFile(file, JSON.stringify(this.exportSession(), null, 2), (err) => {
if (err) return this.emit("error", err);

@@ -362,15 +383,1 @@ });

module.exports = iCloud;
// Small self made fillDefaults method to fill an object with default properties
Object.prototype.fillDefaults = function(defaults) {
Object.keys(defaults).forEach(key => {
if (!(key in this)) {
this[key] = defaults[key];
}
else if (typeof defaults[key] == "object" && defaults[key] != null) {
this[key] = this[key].fillDefaults(defaults[key]);
}
});
return this;
}
{
"name": "apple-icloud",
"version": "1.0.0",
"version": "1.0.2",
"description": "iCloud API",

@@ -36,4 +36,6 @@ "keywords": [

"prompt": "^1.0.0",
"request": "^2.83.0"
"protobufjs": "^6.8.8",
"request": "^2.88.0",
"zlib": "^1.0.5"
}
}

@@ -107,2 +107,12 @@ # iCloud API

#### Save Session automatically
To save the session automatically when something changes, just listen to the `sessionUpdate` event and apply `saveSession()`.
```javascript
myCloud.on("sessionUpdate", function() {
myCloud.saveSession();
});
```
## IMPORTANT

@@ -223,3 +233,3 @@

* [Photos](#photos)
* [Find Me](#find--me)
* [Find Me](#find-me)
* [Reminders](#reminders)

@@ -237,3 +247,3 @@ * [Mail](#mail)

```javascript
myCloud.Calendar.list(function(err, data) {
myCloud.Contacts.list(function(err, data) {
if (err) return console.error(err);

@@ -253,10 +263,8 @@ // Successfully your contacts :)

To change a contact's properties, just replace it's properties and `change(myContact)` it.
To change a contact's properties, just change the object's properties and call `change(myContact)`.
```javascript
myCloud.Calendar.change(myChangedContact, function(err, changeset) { // myChangedContact is just an contact object you got from 'list()'
if (err) return console.error(err);
// Successfully changed
console.log(changeset);
});
myContact.lastName = "NewLastName";
const changeset = await myCloud.Contacts.change(myContact);
```

@@ -271,7 +279,3 @@

```javascript
myCloud.Contacts.delete(myContactIDontLike, function(err, deletedResult) { // myContactIDontLike is just an contact object you got from 'list()'
if (err) return console.error(err);
// Successfully deleted
console.log(deletedResult);
});
const delChangeset = await myCloud.Contacts.delete(myContactIDontLike);
```

@@ -286,3 +290,3 @@

```javascript
myCloud.Contacts.new({
const createChangeset = await myCloud.Contacts.new({
firstName: 'New',

@@ -297,6 +301,2 @@ lastName: 'Guy',

isCompany: false
}, function(err, newContact) {
if (err) return console.error(err);
// Successfully created a new contact
console.log(newContact);
});

@@ -310,7 +310,3 @@ ```

```javascript
myCloud.Friends.getLocations(function(err, locations) {
if (err) return console.error(err);
// Please keep in mind that it doesn't list anything when you call it the first time because the locations are still in progress. But after a few seconds after your first 'initialization' call, it returns the position of your friends.
console.log(locations);
});
const locations = await myCloud.Friends.getLocations();
```

@@ -341,7 +337,3 @@

```javascript
myCloud.Drive.getItem("FOLDER::com.apple.CloudDocs::root", function(err, itemInfo) {
if (err) return console.error(err);
// This is your root folder
console.log(itemInfo);
});
const itemInfo = await myCloud.Drive.getItem("FOLDER::com.apple.CloudDocs::root");
```

@@ -363,5 +355,3 @@

```javascript
myCloud.Drive.getItem("/myFolder/contains/my/nice/item.txt", function(err, itemInfo) {
if (err) return console.error(err);
}, true); // If using folder cache (Only necessary for UNIX paths) (Default is true)
const itemInfo = await myCloud.Drive.getItem("/myFolder/contains/my/nice/item.txt", undefined, true); // If using folder cache (Only necessary for UNIX paths) (Default is true)
```

@@ -394,11 +384,6 @@

```javascript
myCloud.Drive.renameItems({
const changeset = await myCloud.Drive.renameItems({
"/my/item/with/path.txt": "new name.txt", // Of course you can use a drivewsid
"Oh/another/item.txt": "renamed.txt" // Of course you can use a drivewsid
}, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The result is the change set that indicates what you did and in which way you were successfully
console.log(result);
}, true); // If using folder cache (Only necessary for UNIX paths) (Default is true)
}, undefined, true); // If using folder cache (Only necessary for UNIX paths) (Default is true)
```

@@ -416,11 +401,6 @@

```javascript
myCloud.Drive.deleteItems([
const delChangeset = await myCloud.Drive.deleteItems([
"/Test/this folder is new",
"/Test/this folder is also new"
], function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The result is the change set that indicates what you did and in which way you were successfully
console.log(result);
}, true); // If using folder cache (Only necessary for UNIX paths) (Default is true)
], undefined, true); // If using folder cache (Only necessary for UNIX paths) (Default is true)
```

@@ -439,8 +419,3 @@

// 2nd argument: Array with new folders
myCloud.Drive.createFolders("/Test", ["this folder is new"], function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The changeset for your created folders
console.log(result);
}, true); // If using folder cache (Only necessary for UNIX paths) (Default is true)
const createChangeset = await myCloud.Drive.createFolders("/Test", ["this folder is new"], undefined, true); // If using folder cache (Only necessary for UNIX paths) (Default is true)
```

@@ -466,8 +441,3 @@

```javascript
myCloud.Calendar.getCollections(function(err, collections) {
// If an error occurs
if (err) return console.error(err);
// Return the collections
console.log(collections);
});
const collections = await myCloud.Calendar.getCollections();
```

@@ -485,8 +455,3 @@

// Get all events from the 7th July 2017 to 9th August 2017
myCloud.Calendar.getEvents("2017-07-15", "2017-08-09", function(err, events) {
// If an error occurs
if (err) return console.error(err);
// All events in your time area
console.log(events);
});
const events = await myCloud.Calendar.getEvents("2017-07-15", "2017-08-09");
```

@@ -504,11 +469,6 @@

```javascript
myCloud.Calendar.createCollection({
const createChangeset = await myCloud.Calendar.createCollection({
// Properties for your collection (Everything like id's will be calculated automatically)
title: "Mein Kalendar 2!", // The name of the collection
color: "#ffe070" // The color that will be displayed in iCloud clients and represent the collection (Optional default is #ff2d55)
}, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// Return the changeset for the new collection
console.log(result);
});

@@ -529,3 +489,3 @@ ```

```javascript
myCloud.Calendar.createEvent({
const createChangeset = await myCloud.Calendar.createEvent({
title: "Viele", // Required

@@ -553,7 +513,2 @@ location: "My City", // Optional

endDate: new Date("2017-07-26 13:00") // Same here
}, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The changeset of your new event
console.log(result);
});

@@ -602,8 +557,3 @@ ```

// 2nd argument: true - If you want to delete all recurred events ('recurrence') (Default is false)
myCloud.Calendar.deleteEvent(myEventIDontLike, true, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The changeset for your deleted event
console.log(result);
});
const delChangeset = await myCloud.Calendar.deleteEvent(myEventIDontLike, true);
```

@@ -623,8 +573,3 @@

// 2nd argument: true - If you want to change all recurred events ('recurrence') (Default is false)
myCloud.Calendar.changeEvent(myEvent, true, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The changeset for your deleted event
console.log(result);
});
const changeset = await myCloud.Calendar.changeEvent(myEvent, true);
```

@@ -641,8 +586,3 @@

```javascript
myCloud.Photos.get(function(err, images) {
// If an error occurs
if (err) return console.error(err);
// The images list
console.log(images);
});
const images = await myCloud.Photos.get();
```

@@ -667,11 +607,3 @@

```javascript
myCloud.FindMe.get("my.account@mail.com", "totally-save-password", function(err, result) {
// If an error occurs
if (err) return console.error(err);
// Your devices and everything iCloud knows about them
console.log(result);
// Your devices and their positions (if they are avaible)
console.log(result.content);
});
const devices = await myCloud.FindMe.get("my.account@mail.com", "totally-save-password");
```

@@ -692,3 +624,3 @@

// A new call 'get()' will re-initialize everything
myCloud.FindMe.get("my.account@mail.com", "totally-save-password", [Function]);
const devices = await myCloud.FindMe.get("my.account@mail.com", "totally-save-password");
```

@@ -700,7 +632,18 @@

#### Play Sound
### Data
To play sound on a device, use the `playSound()` method.
The method `__data` can be used to get your device's data without
```javascript
// By giving a device's object
await myCloud.FindMe.playSound(myDevice);
// By giving just a device's ID
await myCloud.FindMe.playSound("XXX");
```
To get a device's object, just call `FindMe.get()`. This lists all devices and their related ID.
**Demo:** `demo/findme/playSound.js`
### Reminders

@@ -720,8 +663,3 @@

```javascript
myCloud.Reminders.getOpenTasks(function(err, collections) {
// If an error occurs
if (err) return console.error(err);
// All reminders
console.log(collections);
});
const tasks = await myCloud.Reminders.getOpenTasks();
```

@@ -751,8 +689,3 @@

myCloud.Reminders.deleteTask(myTaskIDontLike, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// Changeset
console.log(result);
});
const delChangeset = await myCloud.Reminders.deleteTask(myTaskIDontLike);
```

@@ -768,8 +701,3 @@

myTask.title = "This is the new title :)"; // Don't use special characters like 'ä', 'ö', etc.
myCloud.Reminders.changeTask(myTask, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// Changeset
console.log(result);
});
const changeset = await myCloud.Reminders.changeTask(myTask);
```

@@ -782,3 +710,3 @@

```javascript
myCloud.Reminders.createTask({
const createChangeset = await myCloud.Reminders.createTask({
title: "I have to do this!",

@@ -788,7 +716,2 @@ pGuid: "tasks", // The 'guid' of a collection

description: "This describes by task perfectly!"
}, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// Changeset & the new task
console.log(result);
});

@@ -814,8 +737,3 @@ ```

myCloud.Reminders.completeTask(myTaskICompleted, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// Changeset
console.log(result);
});
const chageset = await myCloud.Reminders.completeTask(myTaskICompleted);
```

@@ -828,10 +746,5 @@

```javascript
myCloud.Reminders.createCollection({
const createChangeset = await myCloud.Reminders.createCollection({
title: "My new collection",
symbolicColor: "green" // Default 'auto'
}, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// Changeset & the new collection
console.log(result);
});

@@ -851,8 +764,3 @@ ```

myCollection.symbolicColor = "green"; // Sets the symbolic color of the collection to 'green'
myCloud.Reminders.changeCollection(myCollection, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// Changeset
console.log(result);
});
const changeset = await myCloud.Reminders.changeCollection(myCollection);
```

@@ -867,6 +775,3 @@

myCloud.Reminders.deleteCollection(myCollectionIDontLike, function(err, result) {
if (err) return console.error(err);
console.log(result);
});
const delChangeset = await myCloud.Reminders.deleteCollection(myCollectionIDontLike);
```

@@ -887,8 +792,3 @@

```javascript
myCloud.Mail.getFolders(function(err, folders) {
// If an error occurs
if (err) return console.error(err);
// Your folders
console.log(folders);
});
const folders = await myCloud.Mail.getFolders();
```

@@ -906,8 +806,3 @@

// The sort order is descending / newest mails first
myCloud.Mail.listMessages(myFolder, 1, 50, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// Folder's 'meta' and 'messages' data
console.log(result);
});
const messagesData = await myCloud.Mail.listMessages(myFolder, 1, 50);
```

@@ -925,8 +820,3 @@

// 'myMail' is just a message object we got from 'listMessages()'
myCloud.Mail.getMessage(myMail, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// Detailed info about the message
console.log(result);
});
const messageDetail = await myCloud.Mail.getMessage(myMail);
```

@@ -943,11 +833,6 @@

// Has to be an array if you have more than one messages you want to move. If it's only one message, it's message object can be used as argument instead
myCloud.Mail.move([
const changeset = await myCloud.Mail.move([
myMessage1, // The two messages have to be in the same folder!
myMessage2 // Otherwise an error will occur
], destinationFolder, function(err, result) {
// If an error will occur
if (err) return console.error(err);
// The result of your movement
console.log(result);
}); // 2nd argument is the destination folder (folder object)
], destinationFolder); // 2nd argument is the destination folder (folder object)
```

@@ -962,11 +847,6 @@

// Has to be an array if you have more than one messages you want to move. If it's only one message, it's message object can be used as argument instead
myCloud.Mail.delete([
const delChangeset = await myCloud.Mail.delete([
myMessage1,
myMessage2
], function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The result of your deletion
console.log(result);
});
]);
```

@@ -990,11 +870,6 @@

// 2nd argument is the flag you want to add. Possible values are 'flagged' and 'unread'. Default is 'flagged'.
myCloud.Mail.flag([
const flagChangeset = await myCloud.Mail.flag([
myMessages[0],
myMessages[1]
], "flagged", function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The result of flagging
console.log(result);
});
], "flagged");
```

@@ -1009,11 +884,6 @@

// 2nd argument is the flag you want to remove. Possible values are 'flagged' and 'unread'. Default is 'flagged'.
myCloud.Mail.unflag([
const unflagChangeset = await myCloud.Mail.unflag([
myMessages[0],
myMessages[1]
], "unread", function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The result of flagging
console.log(result);
});
], "unread");
```

@@ -1031,3 +901,3 @@

```javascript
myCloud.Mail.send({
const sentment = await myCloud.Mail.send({
//from: "Your Name<your.address@icloud.com>", If not given, your address will be found automatically

@@ -1042,7 +912,2 @@ to: "conr.maur@googlemail.com", // Required

]
}, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The result of your sent mail
console.log(result);
});

@@ -1056,10 +921,5 @@ ```

```javascript
myCloud.Mail.createFolder({
const createChangeset = await myCloud.Mail.createFolder({
name: "My new Folder", // Default null
parent: null // Can be a folder object or a guid string (Default null)
}, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The new folder
console.log(result);
});

@@ -1080,8 +940,3 @@ ```

// 'myTargetFolder' is also just a folder object
myCloud.Mail.moveFolder(myFolder, myTargetFolder, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The result of your movement
console.log(result);
});
const moveChangeset = await myCloud.Mail.moveFolder(myFolder, myTargetFolder);
```

@@ -1100,8 +955,3 @@

// 'myFolder' is just a folder object
myCloud.Mail.renameFolder(myFolder, "New Name", function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The result of your renaming
console.log(result);
});
const renameChangeset = await myCloud.Mail.renameFolder(myFolder, "New Name");
```

@@ -1117,8 +967,3 @@

// 'myFolder' is just a folder object
myCloud.Mail.deleteFolder(myFolder, function(err, result) {
// If an error occurs
if (err) return console.error(err);
// The result of your deletion
console.log(result);
});
const delChangeset = await myCloud.Mail.deleteFolder(myFolder);
```

@@ -1135,49 +980,56 @@

The database of your notes can be very large. And therefore the internal API of Apple uses `records`. A normal iCloud client requests for a *zone* (There is only one zone called *Notes*) and gets just a few notes. Now, if the user scrolls down, more records will be requested. On the one hand, this API is very smart but on the other hand, it's very slow. Therefore I implemented the method `getAll()` which really gets **all** your notes but also takes a lot of time and requests if you have a lot of notes.
That are the bad news.
But the good news are, that a `progress` event fires and returns the current loaded `records`. A `record` can be a `Note` or a `Folder`. The only **problem** is that you may have a Note *record* but the associated *Folder* is not loaded yet. Only if `getAll()` really finishes, you can be completely sure that the folder a Note is associated with, is described in a `record` you also got.
The database of your notes can be very large. And therefore the internal API of Apple uses `records`. A normal iCloud client requests for a *zone* (There is only one zone called *Notes*) and gets just a few notes. Now, if the user scrolls down, more records will be requested. That is the way how Apple's API works.
This is not perfect, I know. But that is the way how Apple's API works and I can not change this generally.
I just can recommend to use the method `getFolder()` because if you got a *Note* `record` but not the `record` of the related *Folder*, you may have a problem. This offers you the possibility to get the folder's data **before** the folder is returned a record.
To make this process more dynamic, use the `fetch()` method which gets all notes as records asynchrounsly.
If the `getAll()` method is finished totally, the result is sorted by folders.
**Note**: By default a Note record
#### Get Notes
#### Fetch Notes
When using `fetch()` all `Note` records will be stored at the `__notes` key within your notes emitter (return of `get()`). If you want to know the parent folder of a note given in `__notes` while the related folder is unknown at the moment, you can use `getFolder()` instead of waiting until the related folder comes trough `get()`.
```javascript
// Get all notes
myCloud.Notes.getAll(function(err, folders) {
// If an error occurs
if (err) return console.error(err);
// Your folders containing the notes
console.log(folders);
});
const notes = myCloud.Notes.fetch();
// Please keep in mind that records coming from "progress" event are not simplified by the API and you have to use them as they are
notes.on("data", zone => {
// Do not use zone by default, the notes are sorted into 'folders'
// There come your records from 'getAll()'
// You may use them before 'getAll()' is finished
myCloud.on("progress", function(event) {
// Relate to the 'getAll()' method
if (event.parentAction === "getAll") {
// The 'zone' object is not important. Important are the 'records' within it
// These records are new and may contain Notes or Folders
// What they are actually containing is described in their object structure
console.log(event.zone.records);
// Here you can have a look at every record's 'parent' property and when the parent folder isn't loaded as record, you can load it manually with 'getFolders()' because it accepts also 'recordName' as arguments
}
// 'folders' is an array containing all notes sorted by folders that are known at this point of time
// Because of the fact, that the folders are coming over a zone, it may takes some time
console.log(notes.folders);
// Just log the notes you already got
//console.log(notes.__notes);
});
notes.on("end", () => {
// Now, you can be sure that EACH folder and EACH note are known
console.log(note.folders);
})
```
**Demo getting all:** `demo/notes/getAll.js`
**Demo:** `demo/notes/fetch.js`
**Demo getting all with progress:** `demo/notes/getAllProgress.js`
#### Resolve Notes
Because `fetch()` returns `Note` records just containing `TitleEncrypted` `SnippetEncrypted` fields, call `resolve()` to get the Note's full content and encode the base64 snippet and title automatically. As arguments pass `Note` records or their `recordName` instead.
```javascript
// Returns array of your notes detailed
const notesDetailed = await myCloud.Notes.resolve(note1, note2); // note1 and note2 are Note record objects or 'recordName' strings
console.log(notesDetailed);
```
**Demo:** `demo/notes/resolveNotes.js`
#### Get Folders
Get folder objects directly. This is important because a `getAll()` call can take a lot of time.
Get folder objects directly. Use this method if you need a Note's parent folder until this folder is unknown at the moment.
```javascript
// 'myFolder1' & 'myFolder2' can be folder objects but also a plain 'recordName' as string (Useful if you know a folder's 'recordName' from a 'Note' record but not it's whole object because it is a record you actually don't have)
myCloud.Notes.getFolders([ // Can also be a single folder object or a single 'recordName' string if it's only one
myCloud.Notes.getFolders([ // Can also be a single folder object or a single 'recordName' string
myFolder1,

@@ -1195,23 +1047,2 @@ myFolder2

#### Get Notes
Because a `getAll()` call can take a lot of time and the note you want may comes very late, you can load a note directly if you already know the whole *Note* object or just it's *record name*.
```javascript
// 'myNote1' & 'myNote2' can be note objects but also a plain 'recordName' as string
myCloud.Notes.getNotes([ // Can also be a single note object or a single 'recordName' string if it's only one
myNote1, // Note object or just a record name
myNote2 // Note object or just a record name
], function(err, notes) {
// If an error occurs
if (err) return console.error(err);
// Array with your note's data
console.log(notes);
});
// This will return all requested notes directly
```
**Demo:** `demo/notes/getNotes.js`
## Push Services

@@ -1218,0 +1049,0 @@

const request = require('request');
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, paramString, paramStr, timeArray, arrayTime} = require("./../helper");
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, paramString, paramStr, timeArray, arrayTime, fillDefaults} = require("./../helper");
module.exports = {
getEvents(startDate, endDate, callback = function() {}) {
var self = this;
var host = getHostFromWebservice(self.account.webservices.calendar);

@@ -23,6 +27,6 @@ var events = [];

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies)
}.fillDefaults(self.clientSettings.defaultHeaders)
}, self.clientSettings.defaultHeaders)
}, function(err, response, body) {

@@ -54,6 +58,6 @@ if (err) {

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies)
}.fillDefaults(self.clientSettings.defaultHeaders)
}, self.clientSettings.defaultHeaders)
}, function(err, response, body) {

@@ -132,6 +136,6 @@ if (err) {

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies)
}.fillDefaults(self.clientSettings.defaultHeaders)
}, self.clientSettings.defaultHeaders)
}, function(err, response, body) {

@@ -172,3 +176,3 @@ if (err) {

//console.log(event.alarms);
event.recurrence = event.recurrence.fillDefaults({
event.recurrence = fillDefaults(event.recurrence, {
pGuid: eventGuid,

@@ -188,3 +192,3 @@ guid: eventGuid + '*MME-RID',

event = event.fillDefaults({
event = fillDefaults(event, {
guid: eventGuid,

@@ -302,7 +306,7 @@ pGuid: 'home',

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -376,3 +380,5 @@ }, function(err, response, body) {

"Collection": [
{
"guid": event.pGuid
}
],

@@ -386,3 +392,2 @@ "fullState": false,

//return console.log(content);

@@ -395,4 +400,3 @@ content = JSON.stringify(content);

request.post("https://" + host + "/ca/events/" + event.pGuid + "/" + event.guid + "/" + ((all && event.recurrence) ? "all" : "") + "?" + paramStr((function() {
var url = "https://" + host + "/ca/events/" + event.pGuid + "/" + event.guid + (event.recurrence ? (all? "/future" : "/this") : "") + "?" + paramStr((function() {
var args = {

@@ -404,9 +408,10 @@ "clientBuildNumber": self.clientSettings.clientBuildNumber,

"dsid": self.account.dsInfo.dsid,
"endDate": "2100-12-31",
"ifMatch": event.etag ? encodeURIComponent(event.etag) : null,
"lang": self.clientSettings.language,
//"startDate": startDate,
//"endDate": endDate,
"usertz": self.clientSettings.timezone,
"methodOverride": methodOverride,
"ifMatch": event.etag ? encodeURIComponent(event.etag) : null
}
"startDate": "1900-01-01",
"usertz": self.clientSettings.timezone
};
if (!args["methodOverride"]) {

@@ -419,10 +424,13 @@ delete args["methodOverride"];

return args;
})()), {
headers: {
})());
request.post(url, {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content
}, function(err, response, body) {
if (err) {

@@ -432,5 +440,13 @@ reject(err);

}
var result = JSON.parse(body);
resolve(result);
callback(null, result);
try {
var result = JSON.parse(body);
resolve(result);
callback(null, result);
}
catch (err) {
reject({
err: err,
body: body
});
}
});

@@ -446,13 +462,1 @@ });

}
Object.prototype.fillDefaults = function(defaults) {
Object.keys(defaults).forEach(key => {
if (!(key in this)) {
this[key] = defaults[key];
}
else if (typeof defaults[key] == "object" && defaults[key] != null) {
this[key] = this[key].fillDefaults(defaults[key]);
}
});
return this;
}
const request = require('request');
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId} = require("./../helper");
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, fillDefaults} = require("./../helper");

@@ -11,6 +11,6 @@

request.get("https://" + host + "/co/startup?clientBuildNumber=" + self.clientSettings.clientBuildNumber + "&clientId=" + self.clientId + "&clientMasteringNumber=" + self.clientSettings.clientMasteringNumber + "&clientVersion=2.1&dsid=" + self.account.dsInfo.dsid + "&locale=de_DE&order=first%2Clast", {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies)
}.fillDefaults(self.clientSettings.defaultHeaders)
}, self.clientSettings.defaultHeaders)
}, function(err, response, body) {

@@ -33,3 +33,3 @@ if (err) {

},
__card(contacts, callback = function() {}, method) {
__card(contacts, callback = function() { }, method) {
var self = this;

@@ -50,9 +50,20 @@

}
var host = getHostFromWebservice(self.account.webservices.contacts);
request.post("https://" + host + "/co/contacts/card/?clientBuildNumber=" + self.clientSettings.clientBuildNumber + "&clientId=" + self.clientId + "&clientMasteringNumber=" + self.clientSettings.clientMasteringNumber + "&clientVersion=2.1&dsid=" + self.account.dsInfo.dsid + "&method=" + method + "&prefToken=" + self.Contacts.prefToken + "&syncToken=" + self.Contacts.syncToken, {
headers: {
request.post("https://" + host + "/co/contacts/card/" +
"?clientBuildNumber=" + self.clientSettings.clientBuildNumber +
"&clientId=" + self.clientId +
"&clientMasteringNumber=" + self.clientSettings.clientMasteringNumber +
"&clientVersion=2.1" +
"&dsid=" + self.account.dsInfo.dsid +
"&locale=en_US" +
"&method=" + method +
"&order=first%2Clast" +
"&prefToken=" + self.Contacts.prefToken +
"&syncToken=" + self.Contacts.syncToken, {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -65,7 +76,11 @@ }, function(err, response, body) {

var result = JSON.parse(body);
if ("errorCode" in result) return callback(result);
if ("errorCode" in result) {
reject(body);
return callback(body);
}
self.Contacts.syncToken = result.syncToken;
self.Contacts.prefToken = result.prefToken;
resolve(result);

@@ -108,3 +123,90 @@ callback(null, result);

return self.Contacts.__card(contacts, callback, "DELETE");
},
__group(groups, callback = function () { }, method) {
var self = this;
var requestPromise = new Promise(function(resolve, reject) {
var content = {
"groups": groups
};
content = JSON.stringify(content);
if (!("syncToken" in self.Contacts)) {
var errorObj = {
error: 'No "syncToken" found! Please call "Contacts.list()" to initialize the Contacts services!',
errorCode: 4
};
reject(errorObj);
return callback(errorObj);
}
var host = getHostFromWebservice(self.account.webservices.contacts);
request.post("https://" + host + "/co/groups/card/" +
"?clientBuildNumber=" + self.clientSettings.clientBuildNumber +
"&clientId=" + self.clientId +
"&clientMasteringNumber=" + self.clientSettings.clientMasteringNumber +
"&clientVersion=2.1" +
"&dsid=" + self.account.dsInfo.dsid +
"&locale=en_US" +
"&method=" + method +
"&order=first%2Clast" +
"&prefToken=" + self.Contacts.prefToken +
"&syncToken=" + self.Contacts.syncToken, {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}, self.clientSettings.defaultHeaders),
body: content
}, function(err, response, body) {
if (err) {
reject(err);
return callback(err);
}
var result = JSON.parse(body);
if ("errorCode" in result) {
reject(body);
return callback(body);
}
self.Contacts.syncToken = result.syncToken;
self.Contacts.prefToken = result.prefToken;
resolve(result);
callback(null, result);
});
});
return requestPromise;
},
newGroups(groups, callback = function () { }) {
var self = this;
if (!(groups instanceof Array)) {
groups = [groups];
}
groups = groups.map(function(group) {
if (!("groupId" in group)) group["groupId"] = newId();
if (!("contactIds" in group)) group["contactIds"] = [];
return group;
});
return self.Contacts.__group(groups, callback, "");
},
deleteGroups(groups, callback = function () { }) {
var self = this;
if (!(groups instanceof Array)) {
groups = [groups];
}
return self.Contacts.__group(groups, callback, "DELETE");
},
changeGroups(groups, callback = function () { }) {
var self = this;
if (!(groups instanceof Array)) {
groups = [groups];
}
return self.Contacts.__group(groups, callback, "PUT");
}
}
const request = require('request');
const https = require('https');
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies} = require("./../helper");
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, fillDefaults} = require("./../helper");

@@ -139,2 +139,3 @@ function isFolder(item) {

function listItem(drivewsid, callback, useCache = true) {
if (drivewsid in self.Drive.folderCache && useCache) {

@@ -145,2 +146,4 @@ callback(null, self.Drive.folderCache[drivewsid], false);

//console.log(self.auth.cookies);
var content = JSON.stringify([

@@ -154,7 +157,7 @@ {

request.post("https://" + host + "/retrieveItemDetailsInFolders?clientBuildNumber=" + self.clientSettings.clientBuildNumber + "&clientId=" + self.clientId + "&clientMasteringNumber=" + self.clientSettings.clientMasteringNumber + "&dsid=" + self.account.dsInfo.dsid, {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -164,2 +167,5 @@ }, function(err, response, body) {

var result = JSON.parse(body);
console.log(result);
if (0 in result) {

@@ -178,6 +184,6 @@ self.Drive.folderCache[result[0].drivewsid] = result[0];

request.get(url, {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies)
}.fillDefaults(self.clientSettings.defaultHeaders)
}, self.clientSettings.defaultHeaders)
}, function(err, response, body) {

@@ -224,7 +230,7 @@ if (err) return callback(err);

request.post("https://" + host + "/createFolders?clientBuildNumber=" + self.clientSettings.clientBuildNumber + "&clientMasteringNumber=" + self.clientSettings.clientMasteringNumber + "&clientId=" + self.clientId + "&dsid=" + self.account.dsInfo.dsid, {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -274,7 +280,7 @@ }, function(err, response, body) {

request.post("https://" + host + "/deleteItems?clientBuildNumber=" + self.clientSettings.clientBuildNumber + "&clientMasteringNumber=" + self.clientSettings.clientMasteringNumber + "&clientId=" + self.clientId + "&dsid=" + self.account.dsInfo.dsid, {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -323,7 +329,7 @@ }, function(err, response, body) {

request.post("https://" + host + "/renameItems?clientBuildNumber=" + self.clientSettings.clientBuildNumber + "&clientMasteringNumber=" + self.clientSettings.clientMasteringNumber + "&clientId=" + self.clientId + "&dsid=" + self.account.dsInfo.dsid, {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -358,7 +364,7 @@ }, function(err, response, body) {

request.post("https://" + host + "/ws/com.apple.CloudDocs/upload/web?token=NONE&clientBuildNumber=" + self.clientSettings.clientBuildNumber + "&clientMasteringNumber=" + self.clientSettings.clientMasteringNumber + "&clientId=1356E574-A2A4-415F-A028-1BC2FB56FFB3&dsid=11298614181", {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -371,7 +377,7 @@ }, function(err, response, body) {

var req = request.post(result[0].url, {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -378,0 +384,0 @@ }, function(err, response, body) {

const request = require('request');
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, paramString, paramStr} = require("./../helper");
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, paramString, paramStr, fillDefaults} = require("./../helper");

@@ -56,7 +56,7 @@ module.exports = {

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -108,12 +108,8 @@ }, function(err, response, body) {

},
__data(callback) {
var self = this;
var host = getHostFromWebservice(self.account.webservices.findme);
// Define request body for post with own properties
var content = JSON.stringify({
__generateContent() {
return {
"serverContext": {
"minCallbackIntervalInMS": 1000,
"enable2FAFamilyActions": false,
"preferredLanguage": self.clientSettings.language,
"preferredLanguage": this.clientSettings.language,
"lastSessionExtensionTime": null,

@@ -132,12 +128,8 @@ "enableMapStats": true,

"sessionLifespan": 900000,
//"info": "/OwnTkNEhM0l5Ba6TZ73nswixOQpymqAaRWQO7lg8S8YJps5Com2xtj5VZ7rIvnX",
//"prefsUpdateTime": 1405254598666,
"useAuthWidget": true,
"clientId": self.clientId,
"clientId": this.clientId,
"enable2FAFamilyRemove": false,
//"serverTimestamp": 1500908149114,
"macCount": 0,
"deviceLoadStatus": "200",
"maxDeviceLoadTime": 60000,
//"prsId": 181764936,
"showSllNow": false,

@@ -151,3 +143,3 @@ "cloudUser": true,

"appVersion": "2.0",
"timezone": self.clientSettings.timezone,
"timezone": this.clientSettings.timezone,
"inactiveTime": 0,

@@ -158,4 +150,11 @@ "apiVersion": "3.0",

}
});
};
},
__data(callback) {
const self = this;
var host = getHostFromWebservice(self.account.webservices.findme);
// Define request body for post with own properties
var content = JSON.stringify(self.FindMe.__generateContent());
// Post the request

@@ -168,7 +167,7 @@ request.post("https://" + host + "/fmipservice/client/web/initClient?" + paramStr({

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -193,2 +192,120 @@ }, function(err, response, body) {

});
},
playSound(device, callback = function() {}) {
const self = this;
const deviceId = typeof device == "object" ? device.id : device;
const content = JSON.stringify(Object.assign(self.FindMe.__generateContent(), {
"device": deviceId,
"subject": "Reminder \u201eFInd my iPhone\u201c"
}));
var host = getHostFromWebservice(this.account.webservices.findme);
return new Promise(function(resolve, reject) {
request.post("https://" + host + "/fmipservice/client/web/playSound?" + paramStr({
"clientBuildNumber": self.clientSettings.clientBuildNumber,
"clientId": self.clientId,
"clientMasteringNumber": self.clientSettings.clientMasteringNumber,
"dsid": self.account.dsInfo.dsid,
}), {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
//'Content-Length': content.length
}, self.clientSettings.defaultHeaders),
body: content
}, function(err, response, body) {
if (err) return callback(err);
try {
// Try to parse the result as JSON (Sometimes it fails because the cookies are invalid)
var result = JSON.parse(body);
} catch (e) {
reject({
error: "Request body is no valid JSON",
errorCode: 13,
requestBody: body
});
return callback({
error: "Request body is no valid JSON",
errorCode: 13,
requestBody: body
});
}
if (result) {
callback(null, result);
resolve(result);
}
});
});
},
lostDevice(device, options, callback = function() {}) {
const self = this;
const deviceId = typeof device == "object" ? device.id : device;
const data = {
"device": deviceId,
"lostModeEnabled": true,
"trackingEnabled": true,
"userText": true,
"text": "",
"emailUpdates": true
};
if (typeof options === 'object' && options.constructor === Object) {
for (let [key, value] of Object.entries(data)) {
if (options.hasOwnProperty(key) && typeof options[key] === typeof value) {
data[key] = options[key]
}
}
}
const content = JSON.stringify(Object.assign(self.FindMe.__generateContent(), data));
var host = getHostFromWebservice(this.account.webservices.findme);
return new Promise(function(resolve, reject) {
request.post("https://" + host + "/fmipservice/client/web/lostDevice?" + paramStr({
"clientBuildNumber": self.clientSettings.clientBuildNumber,
"clientId": self.clientId,
"clientMasteringNumber": self.clientSettings.clientMasteringNumber,
"dsid": self.account.dsInfo.dsid,
}), {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
//'Content-Length': content.length
}, self.clientSettings.defaultHeaders),
body: content
}, function(err, response, body) {
if (err) return callback(err);
try {
// Try to parse the result as JSON (Sometimes it fails because the cookies are invalid)
var result = JSON.parse(body);
} catch (e) {
reject({
error: "Request body is no valid JSON",
errorCode: 13,
requestBody: body
});
return callback({
error: "Request body is no valid JSON",
errorCode: 13,
requestBody: body
});
}
if (result) {
callback(null, result);
resolve(result);
}
});
});
}

@@ -195,0 +312,0 @@ }

const request = require('request');
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, indexOfKey, paramStr} = require("./../helper");
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, indexOfKey, paramStr, fillDefaults} = require("./../helper");

@@ -73,7 +73,7 @@

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content,

@@ -89,6 +89,8 @@ //gzip: true

var cookies = parseCookieStr(response.headers["set-cookie"]);
self.auth.cookies = fillCookies(self.auth.cookies, cookies);
self.auth.cookies = fillCookies(self.auth.cookies, cookies);
var locations = [];
if ("locations" in result) {
var locations = result.locations.map(function(pos) {
locations = result.locations.map(function(pos) {
if (pos.location == null) return {};

@@ -100,3 +102,5 @@ return {

},
adress: pos.location.address,
address: pos.location.address,
accuracy: pos.location.horizontalAccuracy,
timestamp: pos.location.timestamp,
longitude: pos.location.longitude,

@@ -106,6 +110,4 @@ latitude: pos.location.latitude

});
}
else {
var locations = [];
}
}
resolve(locations);

@@ -112,0 +114,0 @@ callback(null, locations);

const request = require('request');
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, paramString, paramStr, timeArray, arrayTime} = require("./../helper");
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, paramString, paramStr, timeArray, arrayTime, fillDefaults} = require("./../helper");

@@ -196,3 +196,3 @@

var from = fullName + "<" + address + ">";
message = message.fillDefaults({
message = fillDefaults(message, {
"date": new Date().toString(),

@@ -237,3 +237,3 @@ "to": null,

var params = folder.fillDefaults({
var params = fillDefaults(folder, {
name: null,

@@ -316,7 +316,7 @@ parent: null

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -359,7 +359,7 @@ }, function(err, response, body) {

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -415,7 +415,7 @@ }, function(err, response, body) {

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -422,0 +422,0 @@ }, function(err, response, body) {

const request = require('request');
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, paramString, paramStr, timeArray, arrayTime} = require("./../helper");
const EventEmitter = require('events');
const protobuf = require('protobufjs');
const zlib = require('zlib');
const path = require('path');
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, paramString, paramStr, timeArray, arrayTime, fillDefaults} = require("./../helper");
module.exports = {
getAll(callback = function() {}) {
fetch() {
var self = this;
var records = [];
const emitter = Object.assign(new EventEmitter(), {
__records: []
});
Object.defineProperty(emitter, "__folders", {
get() {
return this.__records.filter(record => record.recordType === "Folder");
}
});
Object.defineProperty(emitter, "__notes", {
get() {
return this.__records.filter(record => {
return (
//record.shortGUID &&
(record.recordType === "Note" ||
record.recordType === "Note_UserSpecific")
);
});
}
});
Object.defineProperty(emitter, "folders", {
get() {
return this.__folders.map(folder => {
folder.notes = this.__notes.filter(note => {
const noteParentFolder = (() => {
if (note.parent) {
return note.parent;
}
else {
if (note.fields.Folder) {
return note.fields.Folder.value;
}
// Mostly if note is deleted
else {}
}
})();
return noteParentFolder ? (noteParentFolder.recordName === folder.recordName) : undefined;
});
return folder;
});
}
});
requestId = 0;
var notesPromise = new Promise(function(resolve, reject) {
self.Notes.__zone(undefined, handleZone);
function handleZone(err, zone) {
if (err) {
reject(err);
return callback(err);
}
requestId++;
zone.records = zone.records.map(function(record) {
if (record.recordType === "Note") record = simplifyNote(record);
if (record.recordType === "Folder") record = simplifyFolder(record);
delete record.fields;
return record;
});
var requestId = 0;
records = records.concat(zone.records);
self.Notes.__zone(undefined, handleZone);
function handleZone(err, zone) {
if (err) {
reject(err);
return callback(err);
}
self.emit("progress", {
parentAction: "getAll",
action: "loading-records",
progress: null,
requestId: requestId,
zone: zone
});
requestId++;
if (zone.records.length > 0) {
emitter.__records = emitter.__records.concat(zone.records);
emitter.emit("data", zone);
}
if (zone.moreComing) {
self.Notes.__zone(zone.syncToken, handleZone);
}
else {
emitter.emit("end");
}
}
if (zone.moreComing) {
self.Notes.__zone(zone.syncToken, handleZone);
}
else {
var folders = records.filter(record => record.recordType === "Folder");
var notes = records.filter(record => record.recordType === "Note");
return emitter;
},
async resolve(...notes) {
const self = this;
var data = folders.map(function(folder) {
folder.notes = notes.filter(note => note.parent.recordName === folder.recordName);
return folder;
});
const result = await self.Notes.__lookup(notes);
// Simplify data
data.forEach(function(folder) {
return result.records.map(record => {
// Decrypt title & snippet
record.fields.title = decryptBase64(record.fields.TitleEncrypted.value).toString();
record.fields.snippet = decryptBase64(record.fields.SnippetEncrypted.value).toString();
const data = decryptBase64(record.fields.TextDataEncrypted.value);
record.fields.documentData = (data[0] === 0x1f && data[1] === 0x8b) ? zlib.gunzipSync(data) : zlib.inflateSync(data);
// load protobuf definitions
const root = getProtobufRoot();
});
resolve(data);
callback(null, data);
}
}
const Document = root.lookupType("versioned_document.Document");
const StringData = root.lookupType("topotext.String");
record.fields.document = Document.decode(record.fields.documentData);
record.fields.text = StringData.decode(record.fields.document.version[record.fields.document.version.length - 1].data);
return record;
});
return notesPromise;
},
resolveResolve(...notes) {
const self = this;
return new Promise(function(resolve, reject) {
var host = getHostFromWebservice(self.account.webservices.ckdatabasews);
console.log(notes);
const content = JSON.stringify({
/*"shortGUIDs": notes.map(note => ({
"value": typeof note == "string" ? note : note.shortGUID
})),*/
"records": notes.map(note => ({
"recordName": note.recordName
}))
});
console.log(JSON.parse(content));
request.post("https://" + host + "/database/1/com.apple.cloudkit/production/public/records/resolve?" + paramStr({
"clientBuildNumber": self.clientSettings.clientBuildNumber,
"clientId": self.clientId,
"clientMasteringNumber": self.clientSettings.clientMasteringNumber,
"dsid": self.account.dsInfo.dsid
}), {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}, self.clientSettings.defaultHeaders),
body: content
}, function(err, response, body) {
if (err) return callback(err);
var result = JSON.parse(body);
console.log(result);
const records = result.results.map(res => res.rootRecord).map(record => {
// Decrypt title & snippet
record.fields.title = decryptBase64(record.fields.TitleEncrypted.value).toString();
record.fields.snippet = decryptBase64(record.fields.SnippetEncrypted.value).toString();
const data = decryptBase64(record.fields.TextDataEncrypted.value);
record.fields.documentData = (data[0] === 0x1f && data[1] === 0x8b) ? zlib.gunzipSync(data) : zlib.inflateSync(data);
// load protobuf definitions
const root = getProtobufRoot();
const Document = root.lookupType("versioned_document.Document");
const StringData = root.lookupType("topotext.String");
record.fields.document = Document.decode(record.fields.documentData);
record.fields.text = StringData.decode(record.fields.document.version[record.fields.document.version.length - 1].data);
return record;
});
resolve(records);
});
});
},

@@ -77,3 +183,4 @@ __zone(syncToken = undefined, callback = function() {}) {

"zoneID": {
"zoneName": "Notes"
"zoneName": "Notes",
"zoneType": "REGULAR_CUSTOM_ZONE"
},

@@ -83,4 +190,2 @@ "desiredKeys": [

"SnippetEncrypted",
"TextDataEncrypted",
"Content",
"FirstAttachmentUTIEncrypted",

@@ -92,11 +197,13 @@ "FirstAttachmentThumbnail",

"Folders",
"Folder",
"Attachments",
"ParentFolder",
"TextDataAsset",
"Folder",
"Note",
"LastViewedModificationDate"
"LastViewedModificationDate",
"MinimumSupportedNotesVersion"
],
"desiredRecordTypes": [
"Note",
"SearchIndexes",
"Folder",

@@ -106,6 +213,7 @@ "PasswordProtectedNote",

"Users",
"Note_UserSpecific"
"Note_UserSpecific",
"cloudkit.share"
],
"reverse": false,
"syncToken": syncToken
"syncToken": syncToken,
"reverse": true
}

@@ -121,7 +229,7 @@ ]

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -135,34 +243,2 @@ }, function(err, response, body) {

},
getFolders(folders, callback) {
var self = this;
folders = folders instanceof Array ? folders : [folders];
self.Notes.__lookup(folders, function(err, result) {
if (err) {
callback(err);
}
result.forEach(function(record) {
if (record.recordType === "Folder") {
record = simplifyFolder(record);
delete record.fields;
}
});
callback(null, result);
});
},
getNotes(notes, callback) {
var self = this;
notes = notes instanceof Array ? notes : [notes];
self.Notes.__lookup(notes, function(err, result) {
if (err) {
callback(err);
}
result.forEach(function(record) {
if (record.recordType === "Note") {
record = simplifyNote(record);
delete record.fields;
}
});
callback(null, result);
});
},
createFolders(folders, callback) {

@@ -193,34 +269,36 @@ var self = this;

},
__lookup(records, callback) {
__lookup(records) {
var self = this;
var host = getHostFromWebservice(self.account.webservices.ckdatabasews);
return new Promise(function(resolve, reject) {
var host = getHostFromWebservice(self.account.webservices.ckdatabasews);
var content = JSON.stringify({
"records": records.map(record => ({
recordName: typeof record === "object" ? record.recordName : record
})),
"zoneID": {
"zoneName": "Notes"
}
var content = JSON.stringify({
"records": records.map(record => ({
recordName: typeof record === "object" ? record.recordName : record
})),
"zoneID": {
"zoneName": "Notes"
}
});
request.post("https://" + host + "/database/1/com.apple.notes/production/private/records/lookup?" + paramStr({
"clientBuildNumber": self.clientSettings.clientBuildNumber,
"clientId": self.clientId,
"clientMasteringNumber": self.clientSettings.clientMasteringNumber,
"dsid": self.account.dsInfo.dsid,
"remapEnums": true,
"ckjsVersion": "2.0"
}), {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}, self.clientSettings.defaultHeaders),
body: content
}, function(err, response, body) {
if (err) return reject(err);
const result = JSON.parse(body);
resolve(result);
});
});
request.post("https://" + host + "/database/1/com.apple.notes/production/private/records/lookup?" + paramStr({
"clientBuildNumber": self.clientSettings.clientBuildNumber,
"clientId": self.clientId,
"clientMasteringNumber": self.clientSettings.clientMasteringNumber,
"dsid": self.account.dsInfo.dsid,
"remapEnums": true,
"ckjsVersion": "2.0"
}), {
headers: {
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
body: content
}, function(err, response, body) {
if (err) return callback(err);
var result = JSON.parse(body);
callback(null, result.records);
})
},

@@ -240,7 +318,7 @@ __modify(content, callback) {

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -254,16 +332,3 @@ }, function(err, response, body) {

}
function simplifyNote(note) {
note.title = decryptBase64(note.fields.TitleEncrypted.value).toString();
note.snippet = decryptBase64(note.fields.SnippetEncrypted.value).toString();
note.data = decryptBase64(note.fields.TextDataEncrypted.value);
note.parent = note.parent ? note.parent : note.fields.Folders.value[0];
if ("ModificationDate" in note.fields) note.ModificationDate = note.fields.ModificationDate.value;
return note;
}
function simplifyFolder(folder) {
folder.title = decryptBase64(folder.fields.TitleEncrypted.value).toString();
if ("TitleModificationDate" in folder.fields) folder.titleModificationDate = folder.fields.TitleModificationDate.value;
if ("ParentFolder" in folder.fields) folder.parentFolder = folder.fields.ParentFolder.value;
return folder;
}
function decryptBase64(value) {

@@ -275,1 +340,9 @@ return Buffer.from(value, "base64");

}
function getProtobufRoot() {
if (!this.protobufRoot) {
const paths = ["versioned-document.proto", "topotext.proto"/*, "crframework.proto"*/].map(p => path.join(__dirname, '../protobuf/', p));
this.protobufRoot = protobuf.loadSync(paths);
}
return this.protobufRoot;
}
const request = require('request');
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, paramString} = require("./../helper");
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, paramString, fillDefaults} = require("./../helper");

@@ -11,6 +11,6 @@ module.exports = {

request.get("https://" + host + "/database/1/com.apple.photos.cloud/production/private/zones/list?remapEnums=true&ckjsBuildVersion=17DProjectDev77&ckjsVersion=2.0.5&getCurrentSyncToken=true&clientBuildNumber=" + self.clientSettings.clientBuildNumber + "&clientMasteringNumber=" + self.clientSettings.clientMasteringNumber + "&clientId=" + self.clientId + "&dsid=" + self.account.dsInfo.dsid, {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies)
}.fillDefaults(self.clientSettings.defaultHeaders)
}, self.clientSettings.defaultHeaders)
}, function(err, response, body) {

@@ -23,2 +23,3 @@ if (err) {

if ("set-cookie" in response.headers) {

@@ -179,7 +180,7 @@ var cookies = parseCookieStr(response.headers["set-cookie"]);

request.post("https://" + host + "/database/1/com.apple.photos.cloud/production/private/records/query?remapEnums=true&ckjsBuildVersion=17DProjectDev77&ckjsVersion=2.0.5&getCurrentSyncToken=true&clientBuildNumber=" + self.clientSettings.clientBuildNumber + "&clientMasteringNumber=" + self.clientSettings.clientMasteringNumber + "&clientId=" + self.clientId + "&dsid=" + self.account.dsInfo.dsid, {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -212,2 +213,4 @@ }, function(err, response, body) {

console.log(refMetaRecord);
var meta = {

@@ -218,3 +221,3 @@ __recordName: refMetaRecord.recordName,

HDRType: "assetHDRType" in refMetaRecord.fields ? refMetaRecord.fields.assetHDRType.value : null,
timeZoneOffset: refMetaRecord.fields.timeZoneOffset.value,
timeZoneOffset: refMetaRecord.fields.timeZoneOffset ? refMetaRecord.fields.timeZoneOffset.value : null,
duration: "duration" in refMetaRecord.fields ? refMetaRecord.fields.duration.value : 0,

@@ -246,7 +249,7 @@ favorite: ("isFavorite" in refMetaRecord.fields ? refMetaRecord.fields.isFavorite.value : null) ? true : false,

method: "POST",
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders)
}, self.clientSettings.defaultHeaders)
}, function(err, response, body) {

@@ -253,0 +256,0 @@ if (err) return callback(err);

const request = require('request');
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, paramString, paramStr, timeArray, arrayTime} = require("./../helper");
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, paramString, paramStr, timeArray, arrayTime, fillDefaults} = require("./../helper");

@@ -19,6 +19,6 @@ module.exports = {

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies)
}.fillDefaults(self.clientSettings.defaultHeaders)
}, self.clientSettings.defaultHeaders)
}, function(err, response, body) {

@@ -84,3 +84,5 @@ if (err) {

"Collections": [
{
"guid": task.pGuid
}
]

@@ -90,18 +92,8 @@ }

request.post("https://" + host + "/rd/reminders/tasks?" + paramStr({
"clientBuildNumber": self.clientSettings.clientBuildNumber,
"clientId": self.clientId,
"clientMasteringNumber": self.clientSettings.clientMasteringNumber,
"clientVersion": 5.1,
"dsid": self.account.dsInfo.dsid,
"lang": self.clientSettings.language,
"usertz": self.clientSettings.timezone,
"methodOverride": methodOverride || "POST",
"ifMatch": task.etag ? encodeURIComponent(task.etag) : ""
}), {
headers: {
request.post("https://p67-remindersws.icloud.com/rd/reminders/tasks?clientBuildNumber=2003Project34&clientId=b0d019e2-3eca-4e1c-b5a8-907bf9b01721&clientMasteringNumber=2003B27&clientVersion=4.0&dsid=181764936&lang=de-de&usertz=Europe%2FRome", {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
} ,self.clientSettings.defaultHeaders),
body: content

@@ -149,7 +141,7 @@ }, function(err, response, body) {

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -182,6 +174,6 @@ }, function(err, response, body) {

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies)
}.fillDefaults(self.clientSettings.defaultHeaders)
}, self.clientSettings.defaultHeaders)
}, function(err, response, body) {

@@ -213,3 +205,3 @@ if (err) {

task = task.fillDefaults({
task = fillDefaults(task, {
"title": null,

@@ -291,7 +283,7 @@ "description": null,

})()), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -324,3 +316,3 @@ }, function(err, response, body) {

collection = collection.fillDefaults({
collection = fillDefaults(collection, {
"order": 2,

@@ -327,0 +319,0 @@ "title": "New Collection",

const Cookie = require('cookie');
function fillDefaults(a, b) {
Object.keys(b).forEach(key => {
if (!(key in a)) {
a[key] = b[key];
} else if (typeof b[key] == "object" && b[key] != null) {
a[key] = fillDefaults(a[key], b[key]);
}
});
return a;
}
module.exports = {

@@ -78,6 +89,7 @@ getHostFromWebservice(webservice) {

return main;
}
}
},
fillDefaults: fillDefaults
};
Function.prototype.applyConstructor = function(args) {
return new (Function.prototype.bind.apply(this, [null].concat(args)));
}

@@ -7,3 +7,3 @@ (function() {

var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, paramStr} = require("./resources/helper");
var {getHostFromWebservice, cookiesToStr, parseCookieStr, fillCookies, newId, indexOfKey, paramStr, fillDefaults} = require("./resources/helper");

@@ -132,7 +132,7 @@ module.exports = {

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content,

@@ -161,7 +161,7 @@ //gzip: true

}), {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies),
'Content-Length': content.length
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -182,5 +182,3 @@ }, function(err, response, body) {

var req = request.get(uri, {
headers: {
}.fillDefaults(self.clientSettings.defaultHeaders),
headers: fillDefaults({}, self.clientSettings.defaultHeaders),
rejectUnauthorized: false

@@ -223,6 +221,6 @@ }, function(err, response, body) {

request.post(url, {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies)
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -255,6 +253,6 @@ }, function(err, response, body) {

request.post(url, {
headers: {
headers: fillDefaults({
'Host': host,
'Cookie': cookiesToStr(self.auth.cookies)
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: content

@@ -276,3 +274,3 @@ }, function(err, response, body) {

request.get(url, {
headers: {
headers: fillDefaults({
'Referer': signInReferer,

@@ -285,3 +283,3 @@ 'Host': host,

'scnt': self.clientSettings.scnt
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
//body: content

@@ -301,3 +299,3 @@ }, (err, response, body) => {

method: method,
headers: {
headers: fillDefaults({
'Content-Type': 'application/json',

@@ -311,3 +309,3 @@ 'Referer': signInReferer,

'scnt': self.clientSettings.scnt
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: JSON.stringify(bodyObj)

@@ -328,3 +326,3 @@ }, function(err, response, body) {

method: "PUT",
headers: {
headers: fillDefaults({
'Content-Type': 'application/json',

@@ -338,3 +336,3 @@ 'Referer': signInReferer,

'scnt': self.clientSettings.scnt
}.fillDefaults(self.clientSettings.defaultHeaders),
}, self.clientSettings.defaultHeaders),
body: JSON.stringify({

@@ -358,3 +356,3 @@ phoneNumber: {

request.post("https://" + host + "/appleauth/auth/2sv/trust", {
headers: {
headers: fillDefaults({
'Content-Type': 'application/json',

@@ -368,3 +366,3 @@ 'Referer': signInReferer,

'scnt': self.clientSettings.scnt
}.fillDefaults(self.clientSettings.defaultHeaders)
}, self.clientSettings.defaultHeaders)
}, function(err, response, body) {

@@ -371,0 +369,0 @@ if (err) return reject(err);

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc