LoginSignup
3
2

More than 5 years have passed since last update.

Delphi で API キーを分離する

Last updated at Posted at 2016-12-27

これは Delphi Advent Calendar の補欠記事です。

API キー

近年のアプリは他のサービスと連携することが当たり前です。
アプリからあるサービス(API)を利用したいとなったら、そのサービスから「キー」(以下 API キー)を提供して貰うことが多いと思います。

このキーはアプリや個人と結びつくもののため公開してはなりません。

個人で開発しているだけなら良いのですが、ライブラリとして公開したり、サンプルとして公開する場合、API キーを悪用されてしまうかもしれません

API キーの分離

ということで、API キーは分離すべきなのですが、どうやって分離しようかと考えると、例えば

KeyConsts.pas
unit KeyConsts;
interface
const
  API_KEY = 'AE58E0CC-9653-4363-B622-34544D0DE914'
implementation
end.

というユニットを作って、このユニット KeyConsts.pas を .gitignore に追加してアップを防ぐとかです。

まあ、これでも全然良いのですが…

個人的には $I を使っています。

$I コンパイラ指令

$I とは $INCLUDEコンパイラ指令のことです

\$I コンパイラ指令で指定されたファイルは、$I コンパイラ指令の直後に挿入されます。
これを使うとキーをキーだけで分離できます。

KeyConsts.pas
unit KeyConsts;
interface
const
  API_KEY = {$I FooApi.Key};
implementation
end.
FooApi.Key
'AE58E0CC-9653-4363-B622-34544D0DE914'

こんな風に分離して FooApi.Key を .gitignore に追加します。

もしくは、サンプルとして下記の様なダミーの FooApi.Key を入れておいても良いかもしれません。

FooApi.Key
'YOUR_API_KEY'

この場合、もしも FooApi.Key の中身が変更されていない時にエラーで停止できます。

KeyConsts.pas
unit KeyConsts;
interface
const
  API_KEY = {$I FooApi.Key};

{$IF API_KEY  = 'YOUR_API_KEY'}
  {$MESSAGE FATAL 'Foo API のキーを FooApi.Key に記述してください'}
{$ENDIF}

implementation
end.

ただ、これをやるとうっかり本当のキーが書かれた FooApi.Key をアップしてしまうかもしれない諸刃の剣です。
なので、アップしないのが一番でしょう(FooApi.Key が存在しなければコンパイルエラーになるので同じ事です)。

AndroidManifest.xml

そんな感じで $I を使えば API キーを分離できますが、AndroidManifest.xml に記述するタイプのキーとかは中身を置換するのが良いと思います。

Delphi のビルドシステムは MSBuild なので「ビルド前イベント」でバッチファイルや exe を実行できるので、次のようなコンソールアプリを作って

ReplaceAPIKey.dpr
program ReplaceAPIKey;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.Classes, System.SysUtils, System.IOUtils;

const
  MANIFEST = 'AndroidManifest.template.xml';
  ORG_MANIFEST = '_' + MANIFEST;

  API_KEY = 'FooApi.Key'; // 読み込みたい API Key ファイル
  TARGET = '%API_KEY%';   // API Key を書き込む Place Holder

var
  APIKey: String;
begin
  if not TFile.Exists(ORG_MANIFEST) then
    TFile.Copy(MANIFEST, ORG_MANIFEST);

  TFile.Copy(ORG_MANIFEST, MANIFEST, True);

  with TStringList.Create do
    try
      LoadFromFile(API_KEY);
      APIKey := Text.Trim;

      LoadFromFile(MANIFEST, TEncoding.UTF8);
      Text := Text.Replace(Target, APIKEy);
      SaveToFile(MANIFEST, TEncoding.UTF8);
    finally
      DisposeOf;
    end;
end.

ビルド前イベントに追加します。

qiita2.png

もちろん、AndrodManifest.template.xml の方も置き換えるのを忘れないでください。

<meta-data android:name="foo.api.key" android:value="%API_KEY%" />

こんな風にしておくと、ビルド前に自動的に置き換わります。

ただし、注意したいのは Google Map の API キーだけは特別扱いで IDE から設定できます
なので、IDE から設定したキーが記述されている .dproj をアップするとキーも漏洩してしまいます。
これについては悩ましい所ですが、上の仕組みを使って回避するのが良いでしょう。

まとめ

あとは、適当に上手いことやってください!(酷い)

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2