セキュリティ(サンドボックス)

メモ:  Category:javascript

AIRでは、ローカルシステムへのアクセスを提供する代わりにローカルシステムへのセキュリティを確保するため サンドボックスというセキュリティモデルを採用しています。

AIRでは、2つのサンドボックスに分けられて管理されます。 1つは、AIR APIにアクセス可能なアプリケーションサンドボックス、 もうひとつはブラウザ上で動作するのと同じように扱える非アプリケーションサンドボックスになります。

たとえば、Google MAP APIを使用するような場合、2つのHTMLを用意します。

ローカルシステムへアクセスできるroot.html(アプリケーションサンドボックス)、Google MAP APIを利用するui.html(非アプリケーションサンドボックス)これらをiframeなどを使って アプリケーションサンドボックスと非アプリケーションサンドボックスに分けます。

2つのサンドボックスで分けられてしまうため、サンドボックス間の受け渡しが問題になります。これを解決する方法として SandboxBridge APIを使います。

また、JavaScriptライブラリもアプリケーションサンドボックスで使うには、一部制約を受ける場合があります。

Adobeのサイトでは、THIRD-PARTY RESOURCESとして一部のライブラリが 紹介されています。

アプリケーションサンドボックスと非アプリケーションサンドボックスの例

ここでの例は、ローカルにあるgpx(GPSのデータ)を読み込んで非アプリケーションサンドボックスのGoogle Mapへ 軌跡を表示します。

root.html(アプリケーションサンドボックス)を次のように作成します。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" lang="ja" xml:lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>gpx</title>
<link rel="stylesheet" href="./styles.css" type="text/css">
<script type="text/javascript" src="AIRAliases.js" ></script>
<script type="text/javascript" src="AIRIntrospector.js" ></script>
<script type="text/javascript">
var stream;
function openfile() {
    var fileToOpen = new air.File();
    var txtFilter = new air.FileFilter("GPX","*.gpx;*.xml");

    fileToOpen.browseForOpen("Open",[txtFilter]);
    fileToOpen.addEventListener(air.Event.SELECT,fileSelected);
}
function fileSelected( event ) {
    
    var childif = document.getElementById("UI").contentWindow.childSandboxBridge;

    stream = new air.FileStream();
    stream.open(event.target, air.FileMode.READ);
    var gpx = stream.readUTFBytes(stream.bytesAvailable);
    stream.close();

    var domParser = new DOMParser();
    var gpx = domParser.parseFromString(gpx,"text/xml");
    var trkpts = gpx.getElementsByTagName("trkpt");
    
    var points = [];

    for( var i = 0; i < trkpts.length; i++ ) {
        points.push( {
          lat: parseFloat( trkpts[i].attributes["lat"].value ),
          lon: parseFloat( trkpts[i].attributes["lon"].value ) } );
    }

    // 非アプリケーションサンドボックスの関数を呼ぶ
	childif.DrawTrakPoint(points);
}

function init() {
    createMenu();
}
function createMenu() {
    var menu = new air.NativeMenu();
    var filemenu =  new air.NativeMenu();

    filemenu.addItem(new air.NativeMenuItem("Open"));
    filemenu.addItem(new air.NativeMenuItem("",true)); // セパレータ
    filemenu.addItem(new air.NativeMenuItem("Quit"));

    filemenu.items[0].addEventListener(air.Event.SELECT,openfile);

    menu.addSubmenu(filemenu,"File");

    if(air.NativeWindow.supportsMenu) {
        window.nativeWindow.menu = menu;
    }
}
</script>
</head>
<body onload="init()">
<div id="wrap">
    <div id="map">
        <iframe id="UI"
             src="http://localhost/ui.html"
             sandboxRoot="http://localhost/"
             documentRoot="app:/" scrolling="no" height="100%" width="100%">
        </iframe>
    </div>
</div>
</body>
</html>

ui.html(非アプリケーションサンドボックス)を次のように作成します。

<html>
<head>
<title>Google Map</title>
<script src="http://maps.google.com/maps?file=api&v=2" type="text/javascript"></script>
<script type="text/javascript" src="AIRAliases.js" ></script>
<script type="text/javascript">
var DEFAULT_LAT = 35.36497;
var DEFAULT_LNG = 138.72985;
var DEFAULT_ZOOM = 10;

var map = null;

var interface = {};

// 公開する関数(サンドボックスブリッジ)
interface.DrawTrakPoint = function(trkPoints) {
    map.setCenter(new GLatLng(trkPoints[0].lat, trkPoints[0].lon), 13);
    map.addOverlay( new GMarker( new GLatLng(trkPoints[0].lat, trkPoints[0].lon), G_DEFAULT_ICON, true ) );

    var line = [];
    for( var p in trkPoints ) {
        line.push( new GLatLng( trkPoints[p].lat, trkPoints[p].lon ) );
    }

    map.addOverlay( new GPolyline( line ) );
}
window.childSandboxBridge = interface;

// Google Mapの初期化
function initializegmap() {
    if (GBrowserIsCompatible()){
        map = new GMap2(document.getElementById("gmap"));
        map.setCenter(new GLatLng(DEFAULT_LAT,DEFAULT_LNG),DEFAULT_ZOOM);
        map.addControl(new GLargeMapControl());
        map.addControl(new GHierarchicalMapTypeControl());
    }
}
</script>
</head>
<body style="margin:0px;" onload="initializegmap()" onunload="GUnload()">
<div id="gmap" style="width:100%;height:100%;"></div>
</body>
</html>

bluenote by BBB