apple / app-store-server-library-node

MIT License
174 stars 36 forks source link

JWS Decoding Error #187

Closed oanav21 closed 2 months ago

oanav21 commented 2 months ago

Hello,

I've implemented this api to use it to manipulate apple notifications information. Last week, when testing it worked perfectly. Right now, I am always getting "JWS decoding error: ", but with no proper error.

This is my code:

const {SignedDataVerifier, Environment} =
  require("@apple/app-store-server-library");
const fetch = require("node-fetch");

const bundleId = "com.minglr.minglr-app";
const roots = loadCertificates();
const enableOC = true;
const environment = Environment.PRODUCTION;
const appAppleId = "6475294157";
const verifier = new
SignedDataVerifier(roots, enableOC, environment, bundleId, appAppleId); 

exports.payNotifEndpoint = functions.https.onRequest(async (req, res) => {
  try {
    if (req.method !== "POST") {
      res.status(405).send("Method Not Allowed");
      return;
    }

    const signedPayload = req.body.signedPayload;
    if (!signedPayload) {
      res.status(400).send("Missing signed payload");
      return;
    }

    const decoded = jwt.decode(signedPayload, {complete: true});
    const payload = decoded.payload;
    const notificationType = payload.notificationType;
    console.log("Notification type:", notificationType);
    console.log("Decoded Notification Data:", payload);

    switch (notificationType) {
      case "CANCEL":
        await handleCancelNotification(payload);
        break;
      case "DID_RENEW":
      case "INTERACTIVE_RENEWAL":
      case "DID_CHANGE_RENEWAL_STATUS":
        await handleRenewalNotification(payload);
        break;
      default:
        console.log("Unknown notification type: ", notificationType);
    }
    res.status(200).send("Notification processed");
  } catch (error) {
    console.error("Error processing request:", error);
    res.status(400).send("Invalid request payload");
  }
});

async function handleRenewalNotification(notificationData) {
  let transactionDecoded;
  let decodedRenewalInfo;
  try {
    if (!notificationData.data.signedTransactionInfo) {
      throw new
      Error("signedTransactionInfo is missing in notificationData.");
    }
    const trans = notificationData.data.signedTransactionInfo;
    transactionDecoded = await verifier
        .verifyAndDecodeTransaction(trans);
    const renewal = notificationData.data.signedRenewalInfo;
    decodedRenewalInfo = await verifier
        .verifyAndDecodeRenewalInfo(renewal);
    console.log("Decoded R:", JSON.stringify(decodedRenewalInfo, null, 2));
    console.log("Decoded JWS:", JSON.stringify(transactionDecoded, null, 2));
  } catch (error) {
    throw new Error(`JWS decoding error: ${error.message}`);
  }

  const expirationDateMs = transactionDecoded.expiresDate;
  const originalTransactionId = transactionDecoded.originalTransactionId;
  const status = decodedRenewalInfo.autoRenewStatus;
  if (!expirationDateMs || !originalTransactionId || status === undefined) {
    throw new
    Error("Missing originalTransactionId, expirationDateMs, or status.");
  }

  const expirationDate = new Date(parseInt(expirationDateMs, 10));

  let subscriptionStatus;
  switch (status) {
    case 1:
      subscriptionStatus = "active";
      break;
    case 0:
      subscriptionStatus = "expired";
      break;
    default:
      throw new Error(`Unknown autoRenewStatus: ${status}`);
  }

  const usersRef = admin.firestore().collection("users");
  const userSnapshot = await usersRef
      .where("payment.originalTransactionId", "==", originalTransactionId)
      .get();

  if (userSnapshot.empty) {
    throw new Error(`No user found for: ${originalTransactionId}`);
  }

  const updates = [];
  userSnapshot.forEach((doc) => {
    const updatePromise = doc.ref.update({
      "payment.subscriptionStatus": subscriptionStatus,
      "payment.expiration_date": admin.firestore.Timestamp
          .fromDate(expirationDate),
    });
    updates.push(updatePromise);
  });

  await Promise.all(updates);
  console.log(`Updated users with: ${originalTransactionId}`);
}

How should I fix this? I want to mention that I've entered online JWS decoders and the two values are corect for transaction and renewalInfo.

Thank you, Oana V.