keskogt
@keskogt

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Pythonで書かれたLINE Ads APIのサンプルコードをGAS(JavaScript)に翻訳したい

解決したいこと

LINE広告APIドキュメントにてPythonで書かれているサンプルコードを、GAS(JavaScript)で書き直して使いたい

開発の背景

  • LINE広告のパフォーマンスレポートをスプレッドシートに自動で書き出したい
  • 他プラットフォーム(GoogleやYahoo!)の広告データ抽出も行っていることもあり、GASで書きたい

発生しているエラー

{"errors":[{"reason":"Unauthorized","message":"JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted."}]}

「JWT署名がローカルで計算された署名と一致しません。 JWTが有効である確証がないため、信頼すべきではありません」とのこと。

今動かしているソースコード

ドキュメントのPythonのコードを見て、自力でGASに翻訳してみたものが以下です。
サンプルコードは GET /v3/groups/{groupId}/children を使っていたので、 GET /v3/adaccounts/{adaccountId}/campaigns に変えています。

function importAdsReport() {
  const today = new Date();
  const access_key = "xxxxxxxxxxxx";
  const secretKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
  const accountId = "xxxxxxxxxxx";

  const header = `{"alg": "HS256", "kid": "${access_key}", "typ": "text/plain"}`;

  const hex_digest = sha256("");
  const content_type = "";
  const payload_date = Utilities.formatDate(today, 'GMT', 'yyyyMMdd');
  const canonical_url = `/api/v3/adaccounts/${accountId}/campaigns`;
  const payload = `${hex_digest}\n${content_type}\n${payload_date}\n${canonical_url}`;

  const inputValue = `${base64(header)}.${base64(payload)}`;
  const signature = hmacSha256(inputValue, secretKey);
  const calculatedSignature = `${inputValue}.${signature}`;

  const request_headers = {
    "Date": Utilities.formatDate(today, 'GMT', 'E, dd MMM yyyy HH:mm:ss z'),
    "Authorization": `Bearer ${calculatedSignature}`
  }

  const options = {
    "method": "GET",
    "headers": request_headers,
    "muteHttpExceptions": true
  };

  const response = UrlFetchApp.fetch('https://ads.line.me' + canonical_url, options);
}

/**
 * base64エンコード
 * @param {string} input - エンコードしたい文字列
 * @return {string} - base64エンコードされた文字列
 */
function base64(input) {
  return Utilities.base64Encode(input, Utilities.Charset.UTF_8)
}

/**
 * HMAC SHA 256でハッシュ化
 * @param {string} text - ハッシュ化する文字列
 * @param {string} key - ハッシュ化するシークレットキー
 * @return {string} - ハッシュ値
 */
function hmacSha256(text, key) {
  const rowHash = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_256, text, key);
  let txtHash = '';
  for (i = 0; i < rowHash.length; i++) {
    let hashVal = rowHash[i];
    if (hashVal < 0) {
      hashVal += 256;
    }
    if (hashVal.toString(16).length == 1) {
      txtHash += '0';
    }
    txtHash += hashVal.toString(16);
  }
  return txtHash;
};

/**
 * SHA 256でハッシュ化
 * @param {string} input - ハッシュ化する文字列
 * @return {string} - ハッシュ値
 */
function sha256(input) {
  const rawHash = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, input, Utilities.Charset.UTF_8);
  let txtHash = '';
  for (i = 0; i < rawHash.length; i++) {
    let hashVal = rawHash[i];
    if (hashVal < 0) {
      hashVal += 256;
    }
    if (hashVal.toString(16).length == 1) {
      txtHash += '0';
    }
    txtHash += hashVal.toString(16);
  }
  return txtHash
}

エラーの原因っぽいところ

signature が間違っているんだろうと思っています。
HTTPリクエストに渡す calculatedSignatureinputValuesignatureから成っているのですが、 inputValue はPythonで生成したものと一致していました。

Pythonのサンプルコードで

signature = hmac.new(
        secret_key.encode(),
        signing_input.encode(),
        hashlib.sha256
    ).digest()

のように書かれているところを、GASで

const signature = hmacSha256(inputValue, secretKey);

としているのですが、このhmacSha256()がよくないのかなと...。

今試していること

「要するにHS256形式での電子署名生成をGAS(JavaScript)でできればいいのでは」と思い、それらしき記事を見てみたりしているのですが、結局同じエラーが返ってきてしまっています…。

誤っている箇所がお分かりになる方いらっしゃいましたら、ご指摘いただけるととてもありがたいです…。

0

No Answers yet.

Your answer might help someone💌