apple-icloud
Advanced tools
Comparing version 1.0.0 to 1.0.2
@@ -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(); | ||
}); | ||
})(); |
51
main.js
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" | ||
} | ||
} |
385
README.md
@@ -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))); | ||
} |
38
setup.js
@@ -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); |
221019
64
4281
5
1114
+ Addedprotobufjs@^6.8.8
+ Addedzlib@^1.0.5
+ Added@protobufjs/aspromise@1.1.2(transitive)
+ Added@protobufjs/base64@1.1.2(transitive)
+ Added@protobufjs/codegen@2.0.4(transitive)
+ Added@protobufjs/eventemitter@1.1.0(transitive)
+ Added@protobufjs/fetch@1.1.0(transitive)
+ Added@protobufjs/float@1.0.2(transitive)
+ Added@protobufjs/inquire@1.1.0(transitive)
+ Added@protobufjs/path@1.1.2(transitive)
+ Added@protobufjs/pool@1.1.0(transitive)
+ Added@protobufjs/utf8@1.1.0(transitive)
+ Added@types/long@4.0.2(transitive)
+ Added@types/node@20.12.12(transitive)
+ Addedlong@4.0.0(transitive)
+ Addedprotobufjs@6.11.4(transitive)
+ Addedundici-types@5.26.5(transitive)
+ Addedzlib@1.0.5(transitive)
Updatedrequest@^2.88.0