2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.icloud.internal;
15 import static java.nio.charset.StandardCharsets.UTF_8;
17 import java.io.IOException;
19 import java.net.URISyntaxException;
20 import java.time.Duration;
21 import java.util.Base64;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.openhab.binding.icloud.internal.json.request.ICloudAccountDataRequest;
25 import org.openhab.binding.icloud.internal.json.request.ICloudFindMyDeviceRequest;
26 import org.openhab.core.io.net.http.HttpRequestBuilder;
28 import com.google.gson.Gson;
29 import com.google.gson.GsonBuilder;
32 * Handles communication with the Apple server. Provides methods to
33 * get device information and to find a device.
35 * @author Patrik Gfeller - Initial Contribution
36 * @author Patrik Gfeller - SOCKET_TIMEOUT changed from 2500 to 10000
37 * @author Martin van Wingerden - add support for custom CA of https://fmipmobile.icloud.com
40 public class ICloudConnection {
41 private static final String ICLOUD_URL = "https://www.icloud.com";
42 private static final String ICLOUD_API_BASE_URL = "https://fmipmobile.icloud.com";
43 private static final String ICLOUD_API_URL = ICLOUD_API_BASE_URL + "/fmipservice/device/";
44 private static final String ICLOUD_API_COMMAND_PING_DEVICE = "/playSound";
45 private static final String ICLOUD_API_COMMAND_REQUEST_DATA = "/initClient";
46 private static final int SOCKET_TIMEOUT = 15;
48 private final Gson gson = new GsonBuilder().create();
49 private final String iCloudDataRequest = gson.toJson(ICloudAccountDataRequest.defaultInstance());
51 private final String authorization;
52 private final String iCloudDataRequestURL;
53 private final String iCloudFindMyDeviceURL;
55 public ICloudConnection(String appleId, String password) throws URISyntaxException {
56 authorization = new String(Base64.getEncoder().encode((appleId + ":" + password).getBytes()), UTF_8);
57 iCloudDataRequestURL = new URI(ICLOUD_API_URL + appleId + ICLOUD_API_COMMAND_REQUEST_DATA).toASCIIString();
58 iCloudFindMyDeviceURL = new URI(ICLOUD_API_URL + appleId + ICLOUD_API_COMMAND_PING_DEVICE).toASCIIString();
62 * Sends a "find my device" request.
66 public void findMyDevice(String id) throws IOException {
67 callApi(iCloudFindMyDeviceURL, gson.toJson(new ICloudFindMyDeviceRequest(id)));
70 public String requestDeviceStatusJSON() throws IOException {
71 return callApi(iCloudDataRequestURL, iCloudDataRequest);
74 private String callApi(String url, String payload) throws IOException {
76 return HttpRequestBuilder.postTo(url)
77 .withTimeout(Duration.ofSeconds(SOCKET_TIMEOUT))
78 .withHeader("Authorization", "Basic " + authorization)
79 .withHeader("User-Agent", "Find iPhone/1.3 MeKit (iPad: iPhone OS/4.2.1)")
80 .withHeader("Origin", ICLOUD_URL)
81 .withHeader("charset", "utf-8")
82 .withHeader("Accept-language", "en-us")
83 .withHeader("Connection", "keep-alive")
84 .withHeader("X-Apple-Find-Api-Ver", "2.0")
85 .withHeader("X-Apple-Authscheme", "UserIdGuest")
86 .withHeader("X-Apple-Realm-Support", "1.0")
87 .withHeader("X-Client-Name", "iPad")
88 .withHeader("Content-Type", "application/json")
90 .getContentAsString();