UNPKG

policyfile

Version:

Flash Socket Policy File Server. A server to respond to Flash Socket Policy requests, both inline and through a dedicated server instance.

396 lines (353 loc) 24.4 kB
<html> <head> <title>FlashPolicyFileServer</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <style>body { margin: 0; padding: 0; font: 14px/1.5 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; color: #252519; } a { color: #252519; } a:hover { text-decoration: underline; color: #19469D; } p { margin: 12px 0; } h1, h2, h3 { margin: 0; padding: 0; } table#source { width: 100%; border-collapse: collapse; } table#source td:first-child { padding: 30px 40px 30px 40px; vertical-align: top; } table#source td:first-child, table#source td:first-child pre { width: 450px; } table#source td:last-child { padding: 30px 0 30px 40px; border-left: 1px solid #E5E5EE; background: #F5F5FF; } table#source tr { border-bottom: 1px solid #E5E5EE; } table#source tr.filename { padding-top: 40px; border-top: 1px solid #E5E5EE; } table#source tr.filename td:first-child { text-transform: capitalize; } table#source tr.filename td:last-child { font-size: 12px; } table#source tr.filename h2 { margin: 0; padding: 0; cursor: pointer; } table#source tr.code h1, table#source tr.code h2, table#source tr.code h3 { margin-top: 30px; font-family: "Lucida Grande", "Helvetica Nueue", Arial, sans-serif; font-size: 18px; } table#source tr.code h2 { font-size: 16px; } table#source tr.code h3 { font-size: 14px; } table#source tr.code ul { margin: 15px 0 15px 35px; padding: 0; } table#source tr.code ul li { margin: 0; padding: 1px 0; } table#source tr.code ul li p { margin: 0; padding: 0; } table#source tr.code td:first-child pre { padding: 20px; } #ribbon { position: fixed; top: 0; right: 0; } code .string { color: #219161; } code .regexp { color: #219161; } code .keyword { color: #954121; } code .number { color: #19469D; } code .comment { color: #bbb; } code .this { color: #19469D; }</style> <script> $(function(){ $('tr.code').hide(); $('tr.filename').toggle(function(){ $(this).nextUntil('.filename').fadeIn(); }, function(){ $(this).nextUntil('.filename').fadeOut(); }); }); </script> </head> <body> <table id="source"><tbody><tr><td><h1>FlashPolicyFileServer</h1></td><td></td></tr><tr class="filename"><td><h2 id="lib/server.js"><a href="#">server</a></h2></td><td>lib/server.js</td></tr><tr class="code"> <td class="docs"> <p>Module dependencies and cached references. </p> </td> <td class="code"> <pre><code><span class="keyword">var</span> <span class="variable">slice</span> = <span class="class">Array</span>.<span class="variable">prototype</span>.<span class="variable">slice</span> , <span class="variable">net</span> = <span class="variable">require</span>(<span class="string">'net'</span>);</code></pre> </td> </tr> <tr class="code"> <td class="docs"> <p>The server that does the Policy File severing</p> <h2>Options</h2> <ul><li><code>log</code> false or a function that can output log information, defaults to console.log?</li></ul> <h2></h2> <ul><li><p><strong>param</strong>: <em>Object</em> options Options to customize the servers functionality.</p></li><li><p><strong>param</strong>: <em>Array</em> origins The origins that are allowed on this server, defaults to <code>*:*</code>.</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul> </td> <td class="code"> <pre><code><span class="keyword">function</span> <span class="class">Server</span> (<span class="variable">options</span>, <span class="variable">origins</span>) { <span class="keyword">var</span> <span class="variable">me</span> = <span class="this">this</span>; <span class="this">this</span>.<span class="variable">origins</span> = <span class="variable">origins</span> || [<span class="string">'*:*'</span>]; <span class="this">this</span>.<span class="variable">port</span> = <span class="number integer">843</span>; <span class="this">this</span>.<span class="variable">log</span> = <span class="variable">console</span>.<span class="variable">log</span>; <span class="comment">// merge `this` with the options</span> <span class="class">Object</span>.<span class="variable">keys</span>(<span class="variable">options</span>).<span class="variable">forEach</span>(<span class="keyword">function</span> (<span class="variable">key</span>) { <span class="variable">me</span>[<span class="variable">key</span>] &<span class="variable">amp</span>;&<span class="variable">amp</span>; (<span class="variable">me</span>[<span class="variable">key</span>] = <span class="variable">options</span>[<span class="variable">key</span>]) }); <span class="comment">// create the net server</span> <span class="this">this</span>.<span class="variable">socket</span> = <span class="variable">net</span>.<span class="variable">createServer</span>(<span class="keyword">function</span> <span class="variable">createServer</span> (<span class="variable">socket</span>) { <span class="variable">socket</span>.<span class="variable">on</span>(<span class="string">'error'</span>, <span class="keyword">function</span> <span class="variable">socketError</span> () { <span class="variable">me</span>.<span class="variable">responder</span>.<span class="variable">call</span>(<span class="variable">me</span>, <span class="variable">socket</span>); }); <span class="variable">me</span>.<span class="variable">responder</span>.<span class="variable">call</span>(<span class="variable">me</span>, <span class="variable">socket</span>); }); <span class="comment">// Listen for errors as the port might be blocked because we do not have root priv.</span> <span class="this">this</span>.<span class="variable">socket</span>.<span class="variable">on</span>(<span class="string">'error'</span>, <span class="keyword">function</span> <span class="variable">serverError</span> (<span class="variable">err</span>) { <span class="comment">// Special and common case error handling</span> <span class="keyword">if</span> (<span class="variable">err</span>.<span class="variable">errno</span> == <span class="number integer">13</span>) { <span class="variable">me</span>.<span class="variable">log</span> &<span class="variable">amp</span>;&<span class="variable">amp</span>; <span class="variable">me</span>.<span class="variable">log</span>( <span class="string">'Unable to listen to port `'</span> + <span class="variable">me</span>.<span class="variable">port</span> + <span class="string">'` as your Node.js instance does not have root privileges. '</span> + ( <span class="variable">me</span>.<span class="variable">server</span> ? <span class="string">'The Flash Policy File requests will only be served inline over the supplied HTTP server. Inline serving is slower than a dedicated server instance.'</span> : <span class="string">'No fallback server supplied, we will be unable to answer Flash Policy File requests.'</span> ) ); <span class="variable">me</span>.<span class="variable">emit</span>(<span class="string">'connect_failed'</span>, <span class="variable">err</span>); <span class="variable">me</span>.<span class="variable">socket</span>.<span class="variable">removeAllListeners</span>(); <span class="keyword">delete</span> <span class="variable">me</span>.<span class="variable">socket</span>; } <span class="keyword">else</span> { <span class="variable">me</span>.<span class="variable">log</span> &<span class="variable">amp</span>;&<span class="variable">amp</span>; <span class="variable">me</span>.<span class="variable">log</span>(<span class="string">'FlashPolicyFileServer received an error event:\n'</span> + (<span class="variable">err</span>.<span class="variable">message</span> ? <span class="variable">err</span>.<span class="variable">message</span> : <span class="variable">err</span>)); } }); <span class="this">this</span>.<span class="variable">socket</span>.<span class="variable">on</span>(<span class="string">'timeout'</span>, <span class="keyword">function</span> <span class="variable">serverTimeout</span> () {}); <span class="this">this</span>.<span class="variable">socket</span>.<span class="variable">on</span>(<span class="string">'close'</span>, <span class="keyword">function</span> <span class="variable">serverClosed</span> (<span class="variable">err</span>) { <span class="variable">err</span> &<span class="variable">amp</span>;&<span class="variable">amp</span>; <span class="variable">me</span>.<span class="variable">log</span> &<span class="variable">amp</span>;&<span class="variable">amp</span>; <span class="variable">me</span>.<span class="variable">log</span>(<span class="string">'Server closing due to an error: \n'</span> + (<span class="variable">err</span>.<span class="variable">message</span> ? <span class="variable">err</span>.<span class="variable">message</span> : <span class="variable">err</span>)); <span class="keyword">if</span> (<span class="variable">me</span>.<span class="variable">server</span>) { <span class="comment">// Remove the inline policy listener if we close down</span> <span class="comment">// but only when the server was `online` (see listen prototype)</span> <span class="keyword">if</span> (<span class="variable">me</span>.<span class="variable">server</span>[<span class="string">'@'</span>] &<span class="variable">amp</span>;&<span class="variable">amp</span>; <span class="variable">me</span>.<span class="variable">server</span>.<span class="variable">online</span>) { <span class="variable">me</span>.<span class="variable">server</span>.<span class="variable">removeListener</span>(<span class="string">'connection'</span>, <span class="variable">me</span>.<span class="variable">server</span>[<span class="string">'@'</span>]); } <span class="comment">// not online anymore</span> <span class="keyword">delete</span> <span class="variable">me</span>.<span class="variable">server</span>.<span class="variable">online</span>; } }); <span class="comment">// Compile the initial `buffer`</span> <span class="this">this</span>.<span class="variable">compile</span>(); }</code></pre> </td> </tr> <tr class="code"> <td class="docs"> <p>Start listening for requests</p> <h2></h2> <ul><li><p><strong>param</strong>: <em>Number</em> port The port number it should be listening to.</p></li><li><p><strong>param</strong>: <em>Server</em> server A HTTP server instance, this will be used to listen for inline requests</p></li><li><p><strong>param</strong>: <em>Function</em> cb The callback needs to be called once server is ready</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul> </td> <td class="code"> <pre><code><span class="class">Server</span>.<span class="variable">prototype</span>.<span class="variable">listen</span> = <span class="keyword">function</span> <span class="variable">listen</span> (<span class="variable">port</span>, <span class="variable">server</span>, <span class="variable">cb</span>){ <span class="keyword">var</span> <span class="variable">me</span> = <span class="this">this</span> , <span class="variable">args</span> = <span class="variable">slice</span>.<span class="variable">call</span>(<span class="variable">arguments</span>, <span class="number integer">0</span>) , <span class="variable">callback</span>; <span class="comment">// assign the correct vars, for flexible arguments</span> <span class="variable">args</span>.<span class="variable">forEach</span>(<span class="keyword">function</span> <span class="variable">args</span> (<span class="variable">arg</span>){ <span class="keyword">var</span> <span class="variable">type</span> = <span class="keyword">typeof</span> <span class="variable">arg</span>; <span class="keyword">if</span> (<span class="variable">type</span> === <span class="string">'number'</span>) <span class="variable">me</span>.<span class="variable">port</span> = <span class="variable">arg</span>; <span class="keyword">if</span> (<span class="variable">type</span> === <span class="string">'function'</span>) <span class="variable">callback</span> = <span class="variable">arg</span>; <span class="keyword">if</span> (<span class="variable">type</span> === <span class="string">'object'</span>) <span class="variable">me</span>.<span class="variable">server</span> = <span class="variable">arg</span>; }); <span class="keyword">if</span> (<span class="this">this</span>.<span class="variable">server</span>) { <span class="comment">// no one in their right mind would ever create a `@` prototype, so Im just gonna store</span> <span class="comment">// my function on the server, so I can remove it later again once the server(s) closes</span> <span class="this">this</span>.<span class="variable">server</span>[<span class="string">'@'</span>] = <span class="keyword">function</span> <span class="variable">connection</span> (<span class="variable">socket</span>) { <span class="variable">socket</span>.<span class="variable">once</span>(<span class="string">'data'</span>, <span class="keyword">function</span> <span class="variable">requestData</span> (<span class="variable">data</span>) { <span class="comment">// if it's a Flash policy request, and we can write to the </span> <span class="keyword">if</span> ( <span class="variable">data</span> &<span class="variable">amp</span>;&<span class="variable">amp</span>; <span class="variable">data</span>[<span class="number integer">0</span>] === <span class="number integer">60</span> &<span class="variable">amp</span>;&<span class="variable">amp</span>; <span class="variable">data</span>.<span class="variable">toString</span>() === <span class="string">'&lt;policy-file-request/&gt;\0'</span> &<span class="variable">amp</span>;&<span class="variable">amp</span>; <span class="variable">socket</span> &<span class="variable">amp</span>;&<span class="variable">amp</span>; (<span class="variable">socket</span>.<span class="variable">readyState</span> === <span class="string">'open'</span> || <span class="variable">socket</span>.<span class="variable">readyState</span> === <span class="string">'writeOnly'</span>) ){ <span class="comment">// send the buffer</span> <span class="keyword">try</span> { <span class="variable">socket</span>.<span class="variable">end</span>(<span class="variable">me</span>.<span class="variable">buffer</span>); } <span class="keyword">catch</span> (<span class="variable">e</span>) {} } }); }; <span class="comment">// attach it</span> <span class="this">this</span>.<span class="variable">server</span>.<span class="variable">on</span>(<span class="string">'connection'</span>, <span class="this">this</span>.<span class="variable">server</span>[<span class="string">'@'</span>]); } <span class="comment">// We add a callback method, so we can set a flag for when the server is `enabled` or `online`.</span> <span class="comment">// this flag is needed because if a error occurs and the we cannot boot up the server the</span> <span class="comment">// fallback functionality should not be removed during the `close` event</span> <span class="this">this</span>.<span class="variable">port</span> &<span class="variable">gt</span>;= <span class="number integer">0</span> &<span class="variable">amp</span>;&<span class="variable">amp</span>; <span class="this">this</span>.<span class="variable">socket</span>.<span class="variable">listen</span>(<span class="this">this</span>.<span class="variable">port</span>, <span class="keyword">function</span> <span class="variable">serverListening</span> () { <span class="variable">me</span>.<span class="variable">socket</span>.<span class="variable">online</span> = <span class="variable">true</span>; <span class="keyword">if</span> (<span class="variable">callback</span>) { <span class="variable">callback</span>.<span class="variable">call</span>(<span class="variable">me</span>); <span class="variable">callback</span> = <span class="variable">undefined</span>; } }); <span class="keyword">return</span> <span class="this">this</span>; };</code></pre> </td> </tr> <tr class="code"> <td class="docs"> <p>Adds a new origin to the Flash Policy File.</p> <h2></h2> <ul><li><p><strong>param</strong>: <em>Arguments</em> The origins that need to be added.</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul> </td> <td class="code"> <pre><code><span class="class">Server</span>.<span class="variable">prototype</span>.<span class="variable">add</span> = <span class="keyword">function</span> <span class="variable">add</span>(){ <span class="keyword">var</span> <span class="variable">args</span> = <span class="variable">slice</span>.<span class="variable">call</span>(<span class="variable">arguments</span>, <span class="number integer">0</span>) , <span class="variable">i</span> = <span class="variable">args</span>.<span class="variable">length</span>; <span class="comment">// flag duplicates</span> <span class="keyword">while</span> (<span class="variable">i</span>--) { <span class="keyword">if</span> (<span class="this">this</span>.<span class="variable">origins</span>.<span class="variable">indexOf</span>(<span class="variable">args</span>[<span class="variable">i</span>]) &<span class="variable">gt</span>;= <span class="number integer">0</span>){ <span class="variable">args</span>[<span class="variable">i</span>] = <span class="keyword">null</span>; } } <span class="comment">// Add all the arguments to the array</span> <span class="comment">// but first we want to remove all `falsy` values from the args</span> <span class="class">Array</span>.<span class="variable">prototype</span>.<span class="variable">push</span>.<span class="variable">apply</span>( <span class="this">this</span>.<span class="variable">origins</span> , <span class="variable">args</span>.<span class="variable">filter</span>(<span class="keyword">function</span> <span class="variable">filter</span> (<span class="variable">value</span>) { <span class="keyword">return</span> !!<span class="variable">value</span>; }) ); <span class="this">this</span>.<span class="variable">compile</span>(); <span class="keyword">return</span> <span class="this">this</span>; };</code></pre> </td> </tr> <tr class="code"> <td class="docs"> <p>Removes a origin from the Flash Policy File.</p> <h2></h2> <ul><li><p><strong>param</strong>: <em>String</em> origin The origin that needs to be removed from the server</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul> </td> <td class="code"> <pre><code><span class="class">Server</span>.<span class="variable">prototype</span>.<span class="variable">remove</span> = <span class="keyword">function</span> <span class="variable">remove</span> (<span class="variable">origin</span>){ <span class="keyword">var</span> <span class="variable">position</span> = <span class="this">this</span>.<span class="variable">origins</span>.<span class="variable">indexOf</span>(<span class="variable">origin</span>); <span class="comment">// only remove and recompile if we have a match</span> <span class="keyword">if</span> (<span class="variable">position</span> &<span class="variable">gt</span>; <span class="number integer">0</span>) { <span class="this">this</span>.<span class="variable">origins</span>.<span class="variable">splice</span>(<span class="variable">position</span>, <span class="number integer">1</span>); <span class="this">this</span>.<span class="variable">compile</span>(); } <span class="keyword">return</span> <span class="this">this</span>; };</code></pre> </td> </tr> <tr class="code"> <td class="docs"> <p>Closes and cleans up the server</p> <ul><li><p><strong>api</strong>: <em>public</em></p></li></ul> </td> <td class="code"> <pre><code><span class="class">Server</span>.<span class="variable">prototype</span>.<span class="variable">close</span> = <span class="keyword">function</span> <span class="variable">close</span> () { <span class="this">this</span>.<span class="variable">socket</span>.<span class="variable">removeAllListeners</span>(); <span class="keyword">try</span> { <span class="this">this</span>.<span class="variable">socket</span>.<span class="variable">close</span>(); } <span class="keyword">catch</span> (<span class="variable">e</span>) {} <span class="keyword">return</span> <span class="this">this</span>; };</code></pre> </td> </tr> <tr class="code"> <td class="docs"> <p>Proxy the event listener requests to the created Net server </p> </td> <td class="code"> <pre><code><span class="class">Object</span>.<span class="variable">keys</span>(<span class="variable">process</span>.<span class="class">EventEmitter</span>.<span class="variable">prototype</span>).<span class="variable">forEach</span>(<span class="keyword">function</span> <span class="variable">proxy</span> (<span class="variable">key</span>){ <span class="class">Server</span>.<span class="variable">prototype</span>[<span class="variable">key</span>] = <span class="class">Server</span>.<span class="variable">prototype</span>[<span class="variable">key</span>] || <span class="keyword">function</span> () { <span class="keyword">if</span> (<span class="this">this</span>.<span class="variable">socket</span>) { <span class="this">this</span>.<span class="variable">socket</span>[<span class="variable">key</span>].<span class="variable">apply</span>(<span class="this">this</span>.<span class="variable">socket</span>, <span class="variable">arguments</span>); } <span class="keyword">return</span> <span class="this">this</span>; }; });</code></pre> </td> </tr> <tr class="code"> <td class="docs"> <p>Creates a new server instance.</p> <h2></h2> <ul><li><p><strong>param</strong>: <em>Object</em> options A options object to override the default config</p></li><li><p><strong>param</strong>: <em>Array</em> origins The origins that should be allowed by the server</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul> </td> <td class="code"> <pre><code><span class="variable">exports</span>.<span class="variable">createServer</span> = <span class="keyword">function</span> <span class="variable">createServer</span> (<span class="variable">options</span>, <span class="variable">origins</span>) { <span class="variable">origins</span> = <span class="class">Array</span>.<span class="variable">isArray</span>(<span class="variable">origins</span>) ? <span class="variable">origins</span> : (<span class="class">Array</span>.<span class="variable">isArray</span>(<span class="variable">options</span>) ? <span class="variable">options</span> : <span class="variable">false</span>); <span class="variable">options</span> = !<span class="class">Array</span>.<span class="variable">isArray</span>(<span class="variable">options</span>) &<span class="variable">amp</span>;&<span class="variable">amp</span>; <span class="variable">options</span> ? <span class="variable">options</span> : {}; <span class="keyword">return</span> <span class="keyword">new</span> <span class="class">Server</span>(<span class="variable">options</span>, <span class="variable">origins</span>); };</code></pre> </td> </tr> <tr class="code"> <td class="docs"> <p>Provide a hook to the original server, so it can be extended if needed.</p> <h2></h2> <ul><li><p><strong>type</strong>: <em>Net.Server</em> </p></li></ul> </td> <td class="code"> <pre><code><span class="variable">exports</span>.<span class="class">Server</span> = <span class="class">Server</span>;</code></pre> </td> </tr> <tr class="code"> <td class="docs"> <p>Module version</p> <h2></h2> <ul><li><p><strong>type</strong>: <em>String</em> </p></li></ul> </td> <td class="code"> <pre><code><span class="variable">exports</span>.<span class="variable">version</span> = <span class="string">'0.0.5'</span>; </code></pre> </td> </tr> </body> </html></tbody></table>