Example #1
0
  /**
   * Reads a post signer request off the wire, sends it to the WS with a new callback for returning
   * the response.
   *
   * @param request the post signer request
   * @param responseCallback the callback to send the response back
   */
  void processPostSignerRequest(final IQ request, final PacketCallback responseCallback) {
    Element item = null, signatureElement = null;
    Element pubsubRequest = request.getElement().element("pubsub");
    Element publish = pubsubRequest.element("publish");
    if (publish != null) {
      item = publish.element("item");
      if (item != null) {
        signatureElement = item.element("signature");
      }
    }

    if (publish == null
        || item == null
        || signatureElement == null
        || signatureElement.attribute("domain") == null
        || signatureElement.attribute("algorithm") == null
        || signatureElement.element("certificate") == null) {
      responseCallback.error(FederationErrors.badRequest("Malformed post signer request"));
      return;
    }

    ProtocolSignerInfo signer;
    try {
      signer = XmppUtil.xmlToProtocolSignerInfo(signatureElement);
    } catch (UnknownSignerType e) {
      responseCallback.error(
          FederationErrors.badRequest("Could not understand signer algorithm: " + e));
      return;
    }

    WaveletFederationProvider.PostSignerInfoResponseListener listener =
        new WaveletFederationProvider.PostSignerInfoResponseListener() {
          @Override
          public void onFailure(FederationError error) {
            responseCallback.error(error);
          }

          @Override
          public void onSuccess() {
            IQ response = IQ.createResultIQ(request);

            Element pubsub = response.setChildElement("pubsub", XmppNamespace.NAMESPACE_PUBSUB);
            Element item = pubsub.addElement("publish").addElement("item");

            item.addAttribute("node", "signer");
            item.addElement("signature-response", XmppNamespace.NAMESPACE_WAVE_SERVER);

            responseCallback.run(response);
          }
        };

    // TODO(thorogood,arb): This field is a Bad Idea; it could be faked and not
    // be a provider we host on this instance. Instead, we should infer from the
    // "To:" JID.
    String targetDomain = signatureElement.attributeValue("domain");

    // The first argument is the domain we intend to send this information to.
    waveletProvider.postSignerInfo(targetDomain, signer, listener);
  }
Example #2
0
  /**
   * Handles a submit request from a foreign wave remote. Sends it to the wave server, sets up a
   * callback to send the response.
   *
   * @param request the submit request
   * @param responseCallback the callback to send the response back
   */
  void processSubmitRequest(final IQ request, final PacketCallback responseCallback) {
    Element item = null, submitRequest = null, deltaElement = null;
    Element pubsubRequest = request.getElement().element("pubsub");
    // TODO: check for correct elements.
    Element publish = pubsubRequest.element("publish");
    if (publish != null) {
      item = publish.element("item");
      if (item != null) {
        submitRequest = item.element("submit-request");
        if (submitRequest != null) {
          deltaElement = submitRequest.element("delta");
        }
      }
    }
    if (publish == null
        || item == null
        || submitRequest == null
        || deltaElement == null
        || deltaElement.attribute("wavelet-name") == null
        || deltaElement.getText() == null) {
      responseCallback.error(FederationErrors.badRequest("Malformed submit request"));
      return;
    }

    final WaveletName waveletName;
    try {
      waveletName =
          XmppUtil.waveletNameCodec.uriToWaveletName(deltaElement.attributeValue("wavelet-name"));
    } catch (EncodingException e) {
      responseCallback.error(
          FederationErrors.badRequest(
              "Malformed wavelet name: " + deltaElement.attributeValue("wavelet-name")));
      return;
    }

    final ProtocolSignedDelta delta;
    try {
      delta = ProtocolSignedDelta.parseFrom(Base64Util.decode(deltaElement.getText()));
    } catch (InvalidProtocolBufferException e) {
      responseCallback.error(
          FederationErrors.badRequest("Malformed delta, not a valid protocol buffer"));
      return;
    }

    // Construct a submit result listener inline.
    WaveletFederationProvider.SubmitResultListener listener =
        new WaveletFederationProvider.SubmitResultListener() {
          @Override
          public void onFailure(FederationError error) {
            responseCallback.error(error);
          }

          @Override
          public void onSuccess(int operations, ProtocolHashedVersion version, long timestamp) {
            IQ response = IQ.createResultIQ(request);

            Element pubsub = response.setChildElement("pubsub", XmppNamespace.NAMESPACE_PUBSUB);
            Element submitResponse =
                pubsub
                    .addElement("publish")
                    .addElement("item")
                    .addElement("submit-response", XmppNamespace.NAMESPACE_WAVE_SERVER);

            submitResponse.addAttribute("application-timestamp", String.valueOf(timestamp));
            submitResponse.addAttribute("operations-applied", String.valueOf(operations));

            Element hashedVersion = submitResponse.addElement("hashed-version");
            hashedVersion.addAttribute("history-hash", Base64Util.encode(version.getHistoryHash()));
            hashedVersion.addAttribute("version", String.valueOf(version.getVersion()));

            responseCallback.run(response);
          }
        };

    // Hand off the submit request to the wavelet provider.
    waveletProvider.submitRequest(waveletName, delta, listener);
  }
Example #3
0
  /**
   * Reads a get signer request off the wire, sends it to the WS with a new callback for returning
   * the response.
   *
   * @param request the get signer request
   * @param responseCallback the callback to send the response back
   */
  void processGetSignerRequest(final IQ request, final PacketCallback responseCallback) {
    Element items = request.getChildElement().element("items");
    Element signerRequest = items != null ? items.element("signer-request") : null;

    if (items == null
        || signerRequest == null
        || signerRequest.attributeValue("wavelet-name") == null
        || signerRequest.attributeValue("signer-id") == null
        || signerRequest.attributeValue("version") == null
        || signerRequest.attributeValue("history-hash") == null) {
      manager.sendErrorResponse(request, FederationErrors.badRequest("Malformed signer request"));
      return;
    }

    final ByteString signerId;
    try {
      signerId = Base64Util.decode(signerRequest.attributeValue("signer-id"));
    } catch (IllegalArgumentException e) {
      responseCallback.error(FederationErrors.badRequest("Malformed signer ID"));
      return;
    }

    final ProtocolHashedVersion deltaEndVersion;
    try {
      deltaEndVersion =
          parseFromUnsafe(
              signerRequest.attributeValue("version"),
              signerRequest.attributeValue("history-hash"));
    } catch (IllegalArgumentException e) {
      responseCallback.error(FederationErrors.badRequest("Invalid hashed version"));
      return;
    }

    final WaveletName waveletName;
    try {
      waveletName =
          XmppUtil.waveletNameCodec.uriToWaveletName(signerRequest.attributeValue("wavelet-name"));
    } catch (EncodingException e) {
      responseCallback.error(FederationErrors.badRequest("Malformed wavelet name"));
      return;
    }

    WaveletFederationProvider.DeltaSignerInfoResponseListener listener =
        new WaveletFederationProvider.DeltaSignerInfoResponseListener() {
          @Override
          public void onFailure(FederationError error) {
            responseCallback.error(error);
          }

          @Override
          public void onSuccess(ProtocolSignerInfo signerInfo) {
            IQ response = IQ.createResultIQ(request);

            Element pubsub = response.setChildElement("pubsub", XmppNamespace.NAMESPACE_PUBSUB);
            Element items = pubsub.addElement("items");
            XmppUtil.protocolSignerInfoToXml(signerInfo, items);

            responseCallback.run(response);
          }
        };

    waveletProvider.getDeltaSignerInfo(signerId, waveletName, deltaEndVersion, listener);
  }
Example #4
0
  /**
   * Reads a history request off the wire, sends it to the WS with a new callback for returning the
   * response.
   *
   * @param request the history request
   * @param responseCallback the callback to send the response back
   */
  void processHistoryRequest(final IQ request, final PacketCallback responseCallback) {
    Element items = null, historyDelta = null;
    Element pubsubRequest = request.getElement().element("pubsub");
    if (pubsubRequest != null) {
      items = pubsubRequest.element("items");
      if (items != null) {
        historyDelta = items.element("delta-history");
      }
    }
    if (items == null
        || historyDelta == null
        || historyDelta.attribute("start-version") == null
        || historyDelta.attribute("start-version-hash") == null
        || historyDelta.attribute("end-version") == null
        || historyDelta.attribute("end-version-hash") == null
        || historyDelta.attribute("wavelet-name") == null) {
      responseCallback.error(FederationErrors.badRequest("Malformed history request"));
      return;
    }

    final ProtocolHashedVersion startVersion;
    try {
      startVersion =
          parseFromUnsafe(
              historyDelta.attributeValue("start-version"),
              historyDelta.attributeValue("start-version-hash"));
    } catch (IllegalArgumentException e) {
      responseCallback.error(FederationErrors.badRequest("Invalid format of start version"));
      return;
    }

    final ProtocolHashedVersion endVersion;
    try {
      endVersion =
          parseFromUnsafe(
              historyDelta.attributeValue("end-version"),
              historyDelta.attributeValue("end-version-hash"));
    } catch (IllegalArgumentException e) {
      responseCallback.error(FederationErrors.badRequest("Invalid format of end version"));
      return;
    }

    final long responseLengthLimit;
    if (historyDelta.attribute("response-length-limit") != null) {
      try {
        responseLengthLimit = Long.parseLong(historyDelta.attributeValue("response-length-limit"));
      } catch (NumberFormatException e) {
        responseCallback.error(FederationErrors.badRequest("Invalid response length limit"));
        return;
      }
    } else {
      responseLengthLimit = 0;
    }

    final WaveletName waveletName;
    try {
      waveletName =
          XmppUtil.waveletNameCodec.uriToWaveletName(historyDelta.attributeValue("wavelet-name"));
    } catch (EncodingException e) {
      responseCallback.error(
          FederationErrors.badRequest(
              "Malformed wavelet name: " + historyDelta.attributeValue("wavelet-name")));
      return;
    }

    // Construct a new response listener inline.
    WaveletFederationProvider.HistoryResponseListener listener =
        new WaveletFederationProvider.HistoryResponseListener() {
          @Override
          public void onFailure(FederationError error) {
            responseCallback.error(error);
          }

          @Override
          public void onSuccess(
              List<ByteString> appliedDeltaSet,
              ProtocolHashedVersion lastCommittedVersion,
              long versionTruncatedAt) {
            IQ response = IQ.createResultIQ(request);

            Element pubsub = response.setChildElement("pubsub", XmppNamespace.NAMESPACE_PUBSUB);
            Element items = pubsub.addElement("items");

            // Add each delta to the outgoing response.
            for (ByteString appliedDelta : appliedDeltaSet) {
              items
                  .addElement("item")
                  .addElement("applied-delta", XmppNamespace.NAMESPACE_WAVE_SERVER)
                  .addCDATA(Base64Util.encode(appliedDelta.toByteArray()));
            }

            // Set the LCV history-hash, if provided.
            // TODO(thorogood): We don't set the hashed version, which is wrong,
            // but it's not part of the current spec (Feb 2010).
            if (lastCommittedVersion != null && lastCommittedVersion.hasVersion()) {
              String version = String.valueOf(lastCommittedVersion.getVersion());
              items
                  .addElement("item")
                  .addElement("commit-notice", XmppNamespace.NAMESPACE_WAVE_SERVER)
                  .addAttribute("version", version);
            }

            // Set the version truncated at, if provided.
            if (versionTruncatedAt > 0) {
              String version = String.valueOf(versionTruncatedAt);
              items
                  .addElement("item")
                  .addElement("history-truncated", XmppNamespace.NAMESPACE_WAVE_SERVER)
                  .addAttribute("version", version);
            }

            // Send the message to the source.
            responseCallback.run(response);
          }
        };

    // Hand off a history request to the waveletProvider.
    // TODO(thorogood,arb): Note that the following remote domain is going to be
    // the Wave component JID (e.g. wave.foo.com), and *not* the actual remote domain.
    String remoteDomain = request.getFrom().getDomain();
    waveletProvider.requestHistory(
        waveletName, remoteDomain, startVersion, endVersion, responseLengthLimit, listener);
  }