function signUrl(opts, cb) {
	mod_assert.object(opts, 'options');
	mod_assert.optionalNumber(opts.expires, 'options.expires');
	mod_assert.string(opts.host, 'options.host,');
	mod_assert.string(opts.keyId, 'options.keyId');
	mod_assert.string(opts.user, 'options.user');
	mod_assert.string(opts.path, 'options.path');
	mod_assert.optionalObject(opts.query, 'options.query');
	mod_assert.optionalArrayOfString(opts.role, 'options.role');
	mod_assert.optionalArrayOfString(opts['role-tag'],
	    'options[\'role-tag\']');
	mod_assert.optionalString(opts.subuser, 'opts.subuser');
	mod_assert.func(opts.sign, 'options.sign');
	mod_assert.func(opts.sign.getKey, 'options.sign.getKey');
	mod_assert.func(cb, 'callback');
	mod_assert.optionalBool(opts.mantaSubUser, 'options.mantaSubUser');
	mod_assert.optionalString(opts.algorithm, 'options.algorithm');

	if (opts.mantaSubUser && opts.subuser !== undefined)
		opts.user = opts.user + '/' + opts.subuser;
	else if (opts.subuser !== undefined)
		opts.user = opts.user + '/user/' + opts.subuser;

	if (opts.method !== undefined) {
		if (Array.isArray(opts.method)) {
			mod_assert.ok(opts.method.length >= 1);
			opts.method.forEach(function (m) {
				mod_assert.string(m, 'options.method');
			});
		} else {
			mod_assert.string(opts.method, 'options.method');
			opts.method = [opts.method];
		}
	} else {
		opts.method = ['GET', 'HEAD'];
	}
	opts.method.sort();
	var method = opts.method.join(',');

	var q = mod_clone(opts.query || {});
	q.expires = (opts.expires ||
	    Math.floor(((Date.now() + (1000 * 300))/1000)));

	if (opts.role)
		q.role = opts.role.join(',');

	if (opts['role-tag'])
		q['role-tag'] = opts['role-tag'].join(',');

	if (opts.method.length > 1)
		q.method = method;

	opts.sign.getKey(function (err, key) {
		if (err) {
			cb(err);
			return;
		}

		var fp = key.fingerprint('md5').toString('hex');
		q.keyId = '/' + opts.user + '/keys/' + fp;

		q.algorithm = opts.algorithm || opts.sign.algorithm;
		if (q.algorithm === undefined) {
			q.algorithm = key.type + '-' +
			    key.defaultHashAlgorithm();
		}
		q.algorithm = q.algorithm.toUpperCase();

		var line =
		    method + '\n' +
		    opts.host + '\n' +
		    opts.path + '\n';

		var str = Object.keys(q).sort(function (a, b) {
			return (a.localeCompare(b));
		}).map(function (k) {
			return (rfc3986(k) + '=' + rfc3986(q[k]));
		}).join('&');

		line += str;

		if (opts.log)
			opts.log.debug('signUrl: signing -->\n%s', line);

		opts.sign(line, function onSignature(serr, obj) {
			if (serr) {
				cb(serr);
			} else {
				if (obj.algorithm.toUpperCase() !==
				    q.algorithm) {
					if (opts.algorithm === undefined) {
						opts.algorithm = obj.algorithm;
						signUrl(opts, cb);
					} else {
						cb(new Error('The algorithm ' +
						    q.algorithm + ' could not' +
						    ' be used with this key ' +
						    '(try ' + obj.algorithm.
						    toUpperCase() + ')'));
					}
					return;
				}
				var u = opts.path + '?' + str + '&signature=' +
				    rfc3986(obj.signature);
				cb(null, u);
			}
		});
	});
}
/*
 * Creates a presigned URL.
 *
 * Invoke with a signing callback (like other client APIs) and the keys/et al
 * needed to actually form a valid presigned request.
 *
 * Parameters:
 * - host, keyId, user: see other client APIs
 * - sign: needs to have a .getKey() (all the provided signers in smartdc-auth
 *         are fine)
 * - path: URL path to sign
 * - query: optional HTTP query parameters to include on the URL
 * - expires: the expire time of the URL, in seconds since the Unix epoch
 * - mantaSubUser: set to true if using sub-users with Manta
 */
Creates a presigned URL.
Invoke with a signing callback (like other client APIs) and the keys/et al
needed to actually form a valid presigned request.


Creates a presigned URL . Invoke with a signing callback ( like other client APIs ) and the keys / et al needed to actually form a valid presigned request .
function signUrl(opts, cb) {
	mod_assert.object(opts, 'options');
	mod_assert.optionalNumber(opts.expires, 'options.expires');
	mod_assert.string(opts.host, 'options.host,');
	mod_assert.string(opts.keyId, 'options.keyId');
	mod_assert.string(opts.user, 'options.user');
	mod_assert.string(opts.path, 'options.path');
	mod_assert.optionalObject(opts.query, 'options.query');
	mod_assert.optionalArrayOfString(opts.role, 'options.role');
	mod_assert.optionalArrayOfString(opts['role-tag'],
	    'options[\'role-tag\']');
	mod_assert.optionalString(opts.subuser, 'opts.subuser');
	mod_assert.func(opts.sign, 'options.sign');
	mod_assert.func(opts.sign.getKey, 'options.sign.getKey');
	mod_assert.func(cb, 'callback');
	mod_assert.optionalBool(opts.mantaSubUser, 'options.mantaSubUser');
	mod_assert.optionalString(opts.algorithm, 'options.algorithm');
	if (opts.mantaSubUser && opts.subuser !== undefined)
		opts.user = opts.user + '/' + opts.subuser;
	else if (opts.subuser !== undefined)
		opts.user = opts.user + '/user/' + opts.subuser;
	if (opts.method !== undefined) {
		if (Array.isArray(opts.method)) {
			mod_assert.ok(opts.method.length >= 1);
			opts.method.forEach(function (m) {
				mod_assert.string(m, 'options.method');
			});
		} else {
			mod_assert.string(opts.method, 'options.method');
			opts.method = [opts.method];
		}
	} else {
		opts.method = ['GET', 'HEAD'];
	}
	opts.method.sort();
	var method = opts.method.join(',');
	var q = mod_clone(opts.query || {});
	q.expires = (opts.expires ||
	    Math.floor(((Date.now() + (1000 * 300))/1000)));
	if (opts.role)
		q.role = opts.role.join(',');
	if (opts['role-tag'])
		q['role-tag'] = opts['role-tag'].join(',');
	if (opts.method.length > 1)
		q.method = method;
	opts.sign.getKey(function (err, key) {
		if (err) {
			cb(err);
			return;
		}
		var fp = key.fingerprint('md5').toString('hex');
		q.keyId = '/' + opts.user + '/keys/' + fp;
		q.algorithm = opts.algorithm || opts.sign.algorithm;
		if (q.algorithm === undefined) {
			q.algorithm = key.type + '-' +
			    key.defaultHashAlgorithm();
		}
		q.algorithm = q.algorithm.toUpperCase();
		var line =
		    method + '\n' +
		    opts.host + '\n' +
		    opts.path + '\n';
		var str = Object.keys(q).sort(function (a, b) {
			return (a.localeCompare(b));
		}).map(function (k) {
			return (rfc3986(k) + '=' + rfc3986(q[k]));
		}).join('&');
		line += str;
		if (opts.log)
			opts.log.debug('signUrl: signing -->\n%s', line);
		opts.sign(line, function onSignature(serr, obj) {
			if (serr) {
				cb(serr);
			} else {
				if (obj.algorithm.toUpperCase() !==
				    q.algorithm) {
					if (opts.algorithm === undefined) {
						opts.algorithm = obj.algorithm;
						signUrl(opts, cb);
					} else {
						cb(new Error('The algorithm ' +
						    q.algorithm + ' could not' +
						    ' be used with this key ' +
						    '(try ' + obj.algorithm.
						    toUpperCase() + ')'));
					}
					return;
				}
				var u = opts.path + '?' + str + '&signature=' +
				    rfc3986(obj.signature);
				cb(null, u);
			}
		});
	});
}
function signUrl ( opts , cb ) { mod_assert . object ( opts , 'options' ) ; mod_assert . optionalNumber ( opts . expires , 'options.expires' ) ; mod_assert . string ( opts . host , 'options.host,' ) ; mod_assert . string ( opts . keyId , 'options.keyId' ) ; mod_assert . string ( opts . user , 'options.user' ) ; mod_assert . string ( opts . path , 'options.path' ) ; mod_assert . optionalObject ( opts . query , 'options.query' ) ; mod_assert . optionalArrayOfString ( opts . role , 'options.role' ) ; mod_assert . optionalArrayOfString ( opts [ 'role-tag' ] , 'options[\'role-tag\']' ) ; mod_assert . optionalString ( opts . subuser , 'opts.subuser' ) ; mod_assert . func ( opts . sign , 'options.sign' ) ; mod_assert . func ( opts . sign . getKey , 'options.sign.getKey' ) ; mod_assert . func ( cb , 'callback' ) ; mod_assert . optionalBool ( opts . mantaSubUser , 'options.mantaSubUser' ) ; mod_assert . optionalString ( opts . algorithm , 'options.algorithm' ) ; if ( opts . mantaSubUser && opts . subuser !== undefined ) opts . user = opts . user + '/' + opts . subuser ; else if ( opts . subuser !== undefined ) opts . user = opts . user + '/user/' + opts . subuser ; if ( opts . method !== undefined ) { if ( Array . isArray ( opts . method ) ) { mod_assert . ok ( opts . method . length >= 1 ) ; opts . method . forEach ( function ( m ) { mod_assert . string ( m , 'options.method' ) ; } ) ; } else { mod_assert . string ( opts . method , 'options.method' ) ; opts . method = [ opts . method ] ; } } else { opts . method = [ 'GET' , 'HEAD' ] ; } opts . method . sort ( ) ; var method = opts . method . join ( ',' ) ; var q = mod_clone ( opts . query || { } ) ; q . expires = ( opts . expires || Math . floor ( ( ( Date . now ( ) + ( 1000 * 300 ) ) / 1000 ) ) ) ; if ( opts . role ) q . role = opts . role . join ( ',' ) ; if ( opts [ 'role-tag' ] ) q [ 'role-tag' ] = opts [ 'role-tag' ] . join ( ',' ) ; if ( opts . method . length > 1 ) q . method = method ; opts . sign . getKey ( function ( err , key ) { if ( err ) { cb ( err ) ; return ; } var fp = key . fingerprint ( 'md5' ) . toString ( 'hex' ) ; q . keyId = '/' + opts . user + '/keys/' + fp ; q . algorithm = opts . algorithm || opts . sign . algorithm ; if ( q . algorithm === undefined ) { q . algorithm = key . type + '-' + key . defaultHashAlgorithm ( ) ; } q . algorithm = q . algorithm . toUpperCase ( ) ; var line = method + '\n' + opts . host + '\n' + opts . path + '\n' ; var str = Object . keys ( q ) . sort ( function ( a , b ) { return ( a . localeCompare ( b ) ) ; } ) . map ( function ( k ) { return ( rfc3986 ( k ) + '=' + rfc3986 ( q [ k ] ) ) ; } ) . join ( '&' ) ; line += str ; if ( opts . log ) opts . log . debug ( 'signUrl: signing -->\n%s' , line ) ; opts . sign ( line , function onSignature ( serr , obj ) { if ( serr ) { cb ( serr ) ; } else { if ( obj . algorithm . toUpperCase ( ) !== q . algorithm ) { if ( opts . algorithm === undefined ) { opts . algorithm = obj . algorithm ; signUrl ( opts , cb ) ; } else { cb ( new Error ( 'The algorithm ' + q . algorithm + ' could not' + ' be used with this key ' + '(try ' + obj . algorithm . toUpperCase ( ) + ')' ) ) ; } return ; } var u = opts . path + '?' + str + '&signature=' + rfc3986 ( obj . signature ) ; cb ( null , u ) ; } } ) ; } ) ; }
Creates a presigned URL.
Creates a presigned URL .