realm-object-server
Version:
119 lines • 4.96 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const AuthProvider_1 = require("../AuthProvider");
const errors = require("../../errors");
const crypto = require("crypto");
const superagent = require("superagent");
const fs = require("fs-extra");
const cloudKitBaseUri = "https://api.apple-cloudkit.com";
const protocolVersion = 1;
class CloudkitAuthProvider extends AuthProvider_1.AuthProvider {
constructor(config) {
super();
this.name = "cloudkit";
this.options = config;
}
start() {
return __awaiter(this, void 0, void 0, function* () {
this.privateKey = yield fs.readFile(this.options.privateKeyPath, "utf-8");
});
}
authenticateOrCreateUser(body) {
return __awaiter(this, void 0, void 0, function* () {
let userRecordName = body.data;
if (!userRecordName) {
throw new errors.realm.MissingParameters("data");
}
const foundUser = this.service.getUserByProviderId("cloudkit", userRecordName);
if (foundUser) {
return foundUser;
}
const path = this.absoluteDatabasePath("users/discover");
const requestBody = {
lookupInfos: [{ userRecordName }],
};
let response;
try {
response = yield this.signedRequest(path, requestBody);
}
catch (err) {
if (err.response && err.response.body) {
const body = err.response.body;
const reason = body.reason;
if (reason === "No valid user ids to lookup") {
throw new errors.realm.InvalidCredentials();
}
}
throw err;
}
if (response.body.users === undefined) {
throw new Error("Cloutkit: response did not contain any user.");
}
if (response.body.users.length !== 1) {
throw new Error(`Cloudkit: response contained unexpected number of users: ${response.body.users.length}.`);
}
const lookupInfo = userRecordName = response.body.users[0].lookupInfo;
if (!lookupInfo) {
throw new Error("Cloudkit: response did not contain lookupInfo.");
}
userRecordName = lookupInfo.userRecordName;
if (!userRecordName) {
throw new Error("Cloudkit: response did not contain userRecordName.");
}
return this.service.createOrUpdateUser(userRecordName, "cloudkit", false);
});
}
signedRequest(path, body) {
return __awaiter(this, void 0, void 0, function* () {
const date = new Date().toISOString().replace(/.\d{3}(\w+)$/, "$1");
const bodyJson = JSON.stringify(body);
const bodyHash = this.hash(bodyJson);
const signature = this.sign(`${date}:${bodyHash}:${path}`);
const typeRequestHeaders = {
"Accept": "application/json",
"Content-Type": "text/plain",
};
const authRequestHeaders = {
"X-Apple-CloudKit-Request-ISO8601Date": date,
"X-Apple-CloudKit-Request-KeyID": this.options.keyId,
"X-Apple-CloudKit-Request-SignatureV1": signature,
};
const header = Object.assign(typeRequestHeaders, authRequestHeaders);
const url = `${cloudKitBaseUri}${path}`;
return superagent
.post(url)
.set(header)
.send(bodyJson);
});
}
absoluteDatabasePath(path) {
return [
"/database",
protocolVersion,
this.options.container,
this.options.environment,
"public",
path,
].join("/");
}
hash(str) {
const hash = crypto.createHash("sha256");
hash.update(str);
return hash.digest("base64");
}
sign(str) {
const sign = crypto.createSign("RSA-SHA256");
sign.update(str);
return sign.sign(this.privateKey, "base64");
}
}
exports.CloudkitAuthProvider = CloudkitAuthProvider;
//# sourceMappingURL=CloudkitAuthProvider.js.map