Пример #1
0
 char[] generateID(int len) {
   char id[] = new char[len];
   for (int i = 0; i < 10; i++) {
     id[i] = (char) ('a' + crypto.randInt(26));
   }
   return id;
 }
Пример #2
0
public class MegaClient {
  private static final transient org.slf4j.Logger log =
      org.slf4j.LoggerFactory.getLogger(MegaClient.class.getSimpleName());

  static final String API_URL;
  static final String USER_AGENT;

  static {
    ResourceBundle properties = ResourceBundle.getBundle(MegaClient.class.getName());
    API_URL = properties.getString("apiPath");
    USER_AGENT = properties.getString("userAgent");
  }

  transient MegaCrypto crypto = MegaCrypto.get();

  Node currentFolder = null;

  @SuppressWarnings("rawtypes")
  transient LinkedList<Command> cmdQueue = new LinkedList<Command>();

  byte passwordKey[];
  byte masterKey[];
  BigInteger[] privateKey;

  String email;

  User me;

  // no two interrelated client instances should ever have the same sessionid
  @SerializedName("sid")
  String sessionID;

  // request id
  char[] reqid;

  transient String appkey = "MegaJavaTest";

  transient boolean running = false;

  transient ThreadPool threadPool;

  // back off time for server client requests in millis
  transient long backoffsc = 100;

  transient String scnotifyurl = null;

  transient boolean startedSC = false;

  // server-client request sequence number
  String scsn;

  Node rootNode, incomingNode, rubbishNode, mailNode;
  Map<String, Node> nodes;
  HashMap<String, User> users;

  transient HttpURLConnection scConn;

  public MegaClient() {
    super();
  }

  char[] generateID(int len) {
    char id[] = new char[len];
    for (int i = 0; i < 10; i++) {
      id[i] = (char) ('a' + crypto.randInt(26));
    }
    return id;
  }

  public void setSessionID(String sessionID) {
    this.sessionID = sessionID;
  }

  public String getSessionID() {
    return sessionID;
  }

  public void login(String email, String password, final Callback<Void> callback)
      throws IOException {
    log.info("login() {}", email);

    this.email = email.toLowerCase(Locale.getDefault());

    enqueueCommand(
        new CommandLogin(this, password, callback) {
          @Override
          public void processResponse(JsonElement e) throws Exception {
            super.processResponse(e);
            fetchNodes(callback);
          }
        });
  }

  public void fetchNodes(final Callback<Void> callback) throws IOException {
    log.info("fetchNodes();");
    enqueueCommand(new CommandFetchNodes(this, callback));
  }

  public void enqueueCommand(@SuppressWarnings("rawtypes") Command cmd) {
    synchronized (cmdQueue) {
      cmdQueue.addLast(cmd);
      cmdQueue.notify();
    }
  }

  public void enqueueCommands(@SuppressWarnings("rawtypes") List<Command> commands) {
    synchronized (cmdQueue) {
      cmdQueue.addAll(commands);
      cmdQueue.notify();
    }
  }

  public void setEmail(String email) {
    this.email = email;
  }

  public String getEmail() {
    return email;
  }

  public synchronized void start() {
    if (running) return;

    if (threadPool == null) throw new RuntimeException("Thread pool not provided");
    running = true;

    if (sessionID != null) {
      log.info("logged in as: {} with session: {}", email, sessionID);
    }

    // initialize random API request sequence ID

    if (reqid == null) reqid = generateID(10);

    startSC();

    threadPool.background(
        new Runnable() {

          @Override
          public void run() {
            try {
              workerLoop();
            } catch (Throwable t) {
              log.error(t.getMessage(), t);
            } finally {
              MegaClient.this.stop();
            }
          }
        });
  }

  public synchronized void stop() {
    if (!running) return;
    log.info("stop();");
    running = false;
    notifyWorker();
    stopSC();
  }

  @SuppressWarnings("unchecked")
  protected void workerLoop() {

    log.debug("workerLoop();");

    if (scsn != null && sessionID != null) {
      startSC();
    }

    synchronized (cmdQueue) {
      while (running) {
        try {
          cmdQueue.wait();
        } catch (InterruptedException e) {
          log.error(e.getMessage(), e);
          return;
        }
        if (!running) return;

        if (!cmdQueue.isEmpty()) {
          // commands to send
          @SuppressWarnings("rawtypes")
          final LinkedList<Command> commands = (LinkedList<Command>) cmdQueue.clone();
          cmdQueue.clear();

          if (!running) return;

          threadPool.background(
              new Runnable() {

                @Override
                public void run() {
                  log.error("run();");
                  try {
                    processRequest(commands);
                  } catch (IOException e) {
                    handleError(e);
                  }
                }
              });
        }
      }
    }
  }

  public void getAccountDetails(
      boolean storage,
      boolean transfer,
      boolean pro,
      boolean transactions,
      boolean purchases,
      final boolean sessions,
      final Callback<AccountDetails> detailsCallback) {
    final AccountDetails details = new AccountDetails();

    log.info("getAccountDetails() running: {}", this.running);
    @SuppressWarnings("rawtypes")
    LinkedList<Command> commands = new LinkedList<Command>();

    // if (transactions)
    // reqs[r].add(new CommandGetUserTransactions(this, ad));
    // if (purchases)
    // reqs[r].add(new CommandGetUserPurchases(this, ad));

    commands.addLast(
        new CommandGetUserQuota(this, details, storage, transfer, pro) {
          @Override
          public void processResponse(JsonElement e) throws Exception {
            super.processResponse(e);
            if (!sessions) detailsCallback.onResult(details);
          }
        });

    log.warn("transactions,purchases not implemented");

    if (sessions) {
      commands.addLast(
          new Command<AccountDetails>("usl", detailsCallback) {
            @Override
            public void processResponse(JsonElement e) throws Exception {
              details.setSessions(e.getAsJsonArray());
              onResult(details);
            }
          });
    }

    enqueueCommands(commands);
  }

  /**
   * {"a":[{"a":"t","i":"uRHghuyDqJ","t":{"f":[{"h":"9xERwLIa","t":1,"a": "VE8iL_y3eUW1KqOuL6vFfA"
   * ,"k":"XF6DfmTorLE:J6lPWMFvJSw-8IQnGy5vFg","p":"I91ESJKZ" ,"ts":1375206239,"u"
   * :"XF6DfmTorLE"}]},"ou":"XF6DfmTorLE"}],"sn":"QP7kECjmcgE"}
   */
  protected void procsc(JsonObject o) {
    log.trace("procsc() {}", o);

    if (o.has("w")) {
      this.scnotifyurl = o.get("w").getAsString();
    }

    if (o.has("sn")) {
      setScsn(o.get("sn").getAsString());
    }

    if (o.has("a")) {
      log.trace("a: {}", o.get("a"));
      procSC_a(o.get("a").getAsJsonArray());
    }
  }

  protected void procSC_a(JsonArray array) {
    for (int i = 0; i < array.size(); i++) {
      JsonObject o = array.get(i).getAsJsonObject();
      String action = o.get("a").getAsString();
      if (action.equals("u")) {
        log.info("node update");
        // sc_updatenode();
      } else if (action.equals("t")) {
        log.info("node addition");
        // sc_newnodes();
        // mergenewshares();
        // applykeys();

      } else if (action.equals("d")) {
        log.info("node deletion");
        // sc_deltree();

      } else if (action.equals("s")) {
        log.info("share addition/update/revocation");
        // sc_shares();

      } else if (action.equals("c")) {
        log.info("contact addition/update");
        // sc_contacts();

      } else if (action.equals("k")) {
        log.info("crypto key reques");
        // sc_keys();

      } else if (action.equals("fa")) {

      } else if (action.equals("")) {
        log.info("file attribute update");

      } else {
        log.error("unknown action {}", action);
        continue;
      }
    }
  }

  protected void handleError(IOException e) {
    log.error(e.getMessage(), e);
  }

  protected void processRequest(List<Command> commands) throws IOException {
    log.debug("processRequest() ");

    JsonArray payload = new JsonArray();
    for (Command cmd : commands) payload.add(cmd.getPayload());

    StringBuffer url = new StringBuffer(API_URL);

    url.append("cs?id=");
    url.append(reqid);
    if (sessionID != null) url.append("&sid=").append(sessionID);
    if (appkey != null) url.append("&ak=").append(appkey);

    log.debug("url: {}", url);
    HttpURLConnection conn = (HttpURLConnection) new URL(url.toString()).openConnection();

    conn.setDoInput(true);
    conn.setUseCaches(false);
    conn.setRequestProperty("User-Agent", USER_AGENT);
    conn.setRequestProperty("Content-Type", "application/json");
    conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
    conn.setAllowUserInteraction(false);
    conn.setRequestMethod("POST");

    if (payload != null) {
      conn.setDoOutput(true);
      String toPost = payload.toString();
      log.debug("posting: {}", toPost);
      byte data[] = toPost.getBytes("UTF-8");
      conn.setRequestProperty("Content-Length", String.valueOf(data.length));
      OutputStream output = conn.getOutputStream();
      output.write(data);
      output.close();
    }

    int responseCode = conn.getResponseCode();
    String encoding = conn.getContentEncoding();
    int length = conn.getContentLength();
    log.debug("responseCode: " + responseCode + " encoding: {} length: " + length, encoding);

    InputStream input = conn.getInputStream();
    if ("gzip".equals(encoding)) input = new GZIPInputStream(input);

    for (int i = reqid.length - 1; i >= 0; i--) {
      reqid[i] += 1;
      if (reqid[i] < 'z') break;
      else reqid[i] = 'a';
    }

    Reader reader = new BufferedReader(new InputStreamReader(input));
    JsonElement json = GSONUtil.getGSON().fromJson(reader, JsonElement.class);

    log.trace("response: {}", json);

    if (json.isJsonPrimitive()) {
      APIError error = APIError.getError(json.getAsInt());
      for (int i = 0; i < commands.size(); i++) {
        Command cmd = commands.get(i);
        cmd.onError(error);
      }
    } else {

      JsonArray response = json.getAsJsonArray();
      for (int i = 0; i < response.size(); i++) {
        JsonElement e = response.get(i);
        Command cmd = commands.get(i);

        if (e.isJsonPrimitive()) {
          cmd.onError(APIError.getError(e.getAsInt()));
        } else {
          try {
            cmd.processResponse(e);
          } catch (Exception ex) {
            cmd.onError(ex);
          }
        }
      }
    }
  }

  protected void sendSC() {
    if (!running) return;

    try {
      String url = null;

      if (scnotifyurl != null) {
        url = scnotifyurl;
      } else {
        url = API_URL;
        url += "sc";
        url += "?sn=" + scsn;
        url += "&sid=" + sessionID;
      }

      log.debug("sendSC() url {}", url);
      scConn = (HttpURLConnection) new URL(url.toString()).openConnection();

      scConn.setDoInput(true);
      scConn.setDoOutput(false);
      scConn.setRequestProperty("User-Agent", USER_AGENT);
      scConn.setRequestProperty("Content-Type", "application/json");
      scConn.setRequestMethod("POST");

      int responseCode = scConn.getResponseCode();
      String encoding = scConn.getContentEncoding();
      int length = scConn.getContentLength();

      log.debug("responseCode: " + responseCode + " encoding: {} length: " + length, encoding);

      InputStream input = scConn.getInputStream();
      if ("gzip".equals(encoding)) input = new GZIPInputStream(input);

      if (scnotifyurl == null) {
        Reader reader = new BufferedReader(new InputStreamReader(input));
        JsonElement response = GSONUtil.getGSON().fromJson(reader, JsonElement.class);
        procsc(response.getAsJsonObject());
        backoffsc = 100;
        // scnotifyurl will have been set now
      } else {
        scnotifyurl = null;
      }

    } catch (Exception e) {

      if (!running) return;

      if (startedSC) log.error(e.getMessage(), e);
      if (backoffsc < 3600000) backoffsc <<= 1;
      scnotifyurl = null;
    }

    if (!running || !startedSC) return;

    threadPool.background(
        new Runnable() {

          @Override
          public void run() {
            sendSC();
          }
        },
        backoffsc,
        TimeUnit.MILLISECONDS);
  }

  public void setPasswordKey(byte[] passwordKey) {
    this.passwordKey = passwordKey;
  }

  public byte[] getPasswordKey() {
    return passwordKey;
  }

  public void setMasterKey(byte[] masterKey) {
    this.masterKey = masterKey;
  }

  public byte[] getMasterKey() {
    return masterKey;
  }

  public void setPrivateKey(BigInteger[] rsa_private_key) {
    this.privateKey = rsa_private_key;
  }

  public void setScsn(String scsn) {
    log.trace("setScsn(): {}", scsn);
    this.scsn = scsn;
    startSC();
  }

  public void startSC() {
    if (!startedSC && running && scsn != null && sessionID != null) {
      synchronized (this) {
        if (!startedSC && running) {
          startedSC = true;
          threadPool.background(
              new Runnable() {
                @Override
                public void run() {
                  sendSC();
                }
              });
        }
      }
    }
  }

  public synchronized void stopSC() {
    if (!startedSC) return;
    startedSC = false;
    try {
      if (scConn != null) {
        scConn.disconnect();
        scConn = null;
      }
    } catch (Exception ex) {
    }
  }

  public String getScsn() {
    return scsn;
  }

  protected void notifyWorker() {
    synchronized (cmdQueue) {
      cmdQueue.notifyAll();
    }
  }

  public synchronized void clearNodes() {
    rootNode = incomingNode = mailNode = rubbishNode = null;
    nodes = null;
    users = null;
  }

  public Node getRootNode() {
    return rootNode;
  }

  public void setRootNode(Node rootNode) {
    this.rootNode = rootNode;
    if (currentFolder == null) currentFolder = rootNode;
  }

  public Node getIncomingNode() {
    return incomingNode;
  }

  public void setIncomingNode(Node incomingNode) {
    this.incomingNode = incomingNode;
  }

  public Node getRubbishNode() {
    return rubbishNode;
  }

  public User getMe() {
    return me;
  }

  public void setMe(User me) {
    this.me = me;
  }

  public void setRubbishNode(Node rubbishNode) {
    this.rubbishNode = rubbishNode;
  }

  public Node getMailNode() {
    return mailNode;
  }

  public void setMailNode(Node mailNode) {
    this.mailNode = mailNode;
  }

  public void setNodes(HashMap<String, Node> nodes) {
    this.nodes = nodes;
  }

  public List<Node> getChildren() {
    return getChildren(currentFolder);
  }

  public List<Node> getChildren(Node folder) {
    if (nodes == null || folder == null) return Collections.emptyList();

    LinkedList<Node> children = new LinkedList<Node>();
    for (Node n : nodes.values()) {
      if (n.getParent() != null && n.getParent().equals(folder.getHandle())) {
        children.add(n);
      }
    }
    return children;
  }

  public Node getCurrentFolder() {
    return currentFolder;
  }

  public void setCurrentFolder(Node folder) {
    this.currentFolder = folder == null ? rootNode : folder;
  }

  public void applyKeys() {
    log.info("applyKeys()");
    for (Node node : nodes.values()) {
      node.applyKey(this);
    }
  }

  public void setUsers(HashMap<String, User> users) {
    this.users = users;
  }

  public void setAppKey(String appKey) {
    this.appkey = appKey;
  }

  public void setThreadPool(ThreadPool threadPool) {
    this.threadPool = threadPool;
  }

  public void onNodesModified() {
    log.info("onNodesModified()");
  }

  public boolean isLoggedIn() {
    return sessionID != null;
  }

  public Node getNode(String handle) {
    for (Node node : nodes.values()) {
      if (node.getHandle().equals(handle)) return node;
    }
    return null;
  }

  public Node getChildNode(Node parent, String name) {
    for (Node child : getChildren(parent)) {
      if (child.getName().equals(name)) return child;
    }
    return null;
  }

  public Node findNodeByPath(String path) {
    if (rootNode == null) return null;
    if (path.equals("/")) return rootNode;
    String parts[] = path.split("/");
    return findNodeByPath(rootNode, parts, 0);
  }

  private Node findNodeByPath(Node folder, String path[], int index) {
    Node node = getChildNode(folder, path[index]);
    if (index == path.length - 1) return node;
    if (node == null) return null;
    return findNodeByPath(node, path, index + 1);
  }
}