Windows azul: establezca las propiedades CORS de blob utilizando NodeJS

REST API se lanzó en febrero para establecer blobPropiedad CORS, pero esto aún no se ha implementado para NodeJS.

Como necesito esta característica, traté de implementarla en un módulo para mi sitio web azul que ejecuta NodeJS.

Basado en la documentación de la API RESTcambiar las propiedades de CORS y paragenerar clave de autenticación, enesta implementación de la generación de claves de autenticación utilizando NodeJS, traté de seguir la respuesta aceptada deesta Publicar, pero no funcionó para mí.

Esto es lo que tengo en setcrosproperties.js:

var crypto = require('crypto');
var request = require('request');


exports.setCors = function (MY_ACCOUNT_URL, MY_ACCOUNT_NAME, MY_ACCOUNT_HOST, accountKey) {
    var MY_CORS_XML =
    '<?xml version="1.0" encoding="utf-8"?>'+
        '<StorageServiceProperties>'+
            '<Cors>'+
                '<CorsRule>'+
                    '<AllowedOrigins>*</AllowedOrigins>'+
                    '<AllowedMethods>GET,PUT</AllowedMethods>'+
                    '<MaxAgeInSeconds>500</MaxAgeInSeconds>'+
                    '<ExposedHeaders>x-ms-meta-data*,x-ms-meta-customheader</ExposedHeaders>'+
                    '<AllowedHeaders>x-ms-meta-target*,x-ms-meta-customheader</AllowedHeaders>'+
                '</CorsRule>'+
            '</Cors>'+
            '<DefaultServiceVersion>2013-08-15</DefaultServiceVersion>'+
        '</StorageServiceProperties>';


    var url = MY_ACCOUNT_URL + '/?restype=service&comp=properties';
    var canonicalizedResource = '/' + MY_ACCOUNT_NAME + '/?comp=properties';
    var corsMD5 = crypto.createHash('md5' ).update(MY_CORS_XML).digest('base64');
    var date = (new Date()).toUTCString();
    var headers = {
        'x-ms-version': '2013-08-15',
        'x-ms-date': date,
        'Host': MY_ACCOUNT_HOST
    };

    var canonicalizedHeaders = buildCanonicalizedHeaders( headers );

    // THIS
    var key = buildSharedKeyLite( 'PUT', corsMD5, 'text/plain; charset=UTF-8', canonicalizedHeaders, canonicalizedResource, accountKey);

    // AND THIS, BOTH YIELD THE SAME SERVER RESPONSE
    // var key = buildSharedKeyLite( 'PUT', "", "", canonicalizedHeaders, canonicalizedResource, accountKey);

    headers['Authorization'] = 'SharedKeyLite ' + MY_ACCOUNT_NAME + ':' + key;

    var options = {
        url: url,
        body: MY_CORS_XML,
        headers: headers
    };

    console.log("url : " + url);
    console.log("canonicalizedResource : " + canonicalizedResource);
    console.log("canonicalizedHeaders : " + canonicalizedHeaders);
    console.log("corsMD5 : " + corsMD5);
    console.log("key : " + key);
    console.log("options : " + JSON.stringify(options));

    function onPropertiesSet(error, response, body) {
        if (!error && response.statusCode == 202) {
            console.log("CORS: OK");
        }
        else {
            console.log("CORS: " + response.statusCode);
            console.log("body : " + body);
        }
    }
    request.put(options, onPropertiesSet); // require('request')
};

function buildCanonicalizedHeaders( headers ) {

    var xmsHeaders = [];
    var canHeaders = "";

    for ( var name in headers ) {
        if ( name.indexOf('x-ms-') == 0 ) {
            xmsHeaders.push( name );
        }
    }

    xmsHeaders.sort();

    for ( var i = 0; i < xmsHeaders.length; i++ ) {
        name = xmsHeaders[i];
        canHeaders = canHeaders + name.toLowerCase().trim() + ':' + headers[name] + '\n';
    }
    return canHeaders;
}

function buildSharedKeyLite( verb, contentMD5, contentType, canonicalizedHeaders, canonicalizedResource, accountKey) {

    var stringToSign = verb + "\n" +
        contentMD5 + "\n" +
        contentType + "\n" +
        "" + "\n" + // date is to be empty because we use x-ms-date
        canonicalizedHeaders +
        canonicalizedResource;

    // return crypto.createHmac('sha256', accountKey).update(encodeURIComponent(stringToSign)).digest('base64');
    return crypto.createHmac('sha256', new Buffer(accountKey, 'base64')).update(stringToSign).digest('base64');
}

Y así es como llamo a esta función desde mi archivo server.js:

var setcrosproperties = require('./setcrosproperties.js');
// setCors(MY_ACCOUNT_URL, MY_ACCOUNT_NAME, MY_ACCOUNT_HOST, accountKey)
setcrosproperties.setCors(
    'https://'+process.env['AZURE_STORAGE_ACCOUNT']+'.blob.core.windows.net',
    process.env['AZURE_STORAGE_ACCOUNT'],
    process.env['AZURE_STORAGE_ACCOUNT']+'.blob.core.windows.net',
    process.env['AZURE_STORAGE_ACCESS_KEY']);

No entendí cuál era la diferencia prevista con las variables MY_ACCOUNT_UTL (asumí URL) y MY_ACCOUNT_HOST, por lo que utilizo el mismo valor para ambos parámetros de la función.

(Eliminé el parámetro "cors", que parecía no estar usado).

Esto es lo que obtengo en la consola:

url:https://NAME_OF_MY_STORAGE_ACCOUNT.blob.core.windows.net/?restype=service&comp=properties&nbsp;canonicalizedResource: / NAME_OF_MY_STORAGE_ACCOUNT /? comp = properties canonicalizedHeaders: x-ms-date: Sun, 09 Mar 2014 12:33:41 GMT x-ms-version: 2013-08-15 corsMD5: + ij ... w == key : sNB ... JrY = opciones: {"url": "https://NAME_OF_MY_STORAGE_ACCOUNT.blob.core.windows.net/?restype=service&comp=properties","cuerpo":"OBTENER, PUT500x-ms-meta-data, x-ms-meta-customheaderx-ms-meta-target *, x-ms-meta-customheader2013-08-15 "," encabezados ": {" x-ms-version ":" 2013-08-15 ", "x-ms-date": "Dom, 09 mar 2014 12:33:41 GMT", "Host": "NAME_OF_MY_STORAGE_ACCOUNT.blob.core.windows.net", "Autorización": "SharedKeyLite NAME_OF_MY_STORAGE_ACCOUNT: sNB ... rY = "}} CORS: 403 cuerpo:AuthenticationFailedEl servidor no pudo autenticar la solicitud. Asegúrese de que el valor del encabezado de autorización esté formado correctamente, incluida la firma. RequestId: 1e6abfe3-e0e8-4b9c-922d-7cb34485eec9 Hora: 2014-03-09T12: 33: 41.7262308Z La firma MAC encontrada en la solicitud HTTP 'sNB ... JrY =' no es la misma que cualquier firma calculada. El servidor usó la siguiente cadena para firmar: 'PUT

x-ms-date: dom, 09 mar 2014 12:33:41 GMT x-ms-version: 2013-08-15 / NAME_OF_MY_STORAGE_ACCOUNT /? comp = properties '.

¿Alguna idea de lo que estoy haciendo mal aquí? Gracias por tu ayuda