Generate AWS Signature in MarkLogic XQuery - can't reproduce example hash - xquery

I need to send a GET request to AWS from MarkLogic and sign the URL. I was using the AWS documentation to understand how the signature gets created but what I get and what I expect to get aren't the same.
Sample data is from this page.
let $canonicalRequest :=
'GET
/test.txt
X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host
host:examplebucket.s3.amazonaws.com
host
UNSIGNED-PAYLOAD'
(: the value of this is correct, this is the same as the example, 3bfa292879f6447bbcda7001decf97f4a54dc650c8942174ae0a9121cf58ad04 :)
let $canonicalRequestHash := xdmp:sha256($canonicalRequest)
let $stringToSign :=
'AWS4-HMAC-SHA256
20130524T000000Z
20130524/us-east-1/s3/aws4_request
' ||
$canonicalRequestHash
let $signingKey := xdmp:hmac-sha256(xdmp:hmac-sha256(xdmp:hmac-sha256(xdmp:hmac-sha256("AWS4wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY","20130524"),"us-east-1"),"s3"),"aws4_request")
return xdmp:hmac-sha256($signingKey,$stringToSign)
I get
ec43271c228d0d408e25dd8ec1e3b71ed7c1dbfe5c76bd7f272d3bff665e1f16
I would like to get
aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404

The secretKey parameter should be a binary node for the region, service, and signing keys. This should work:
xquery version "1.0-ml";
let $canonicalRequest :=
'GET
/test.txt
X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host
host:examplebucket.s3.amazonaws.com
host
UNSIGNED-PAYLOAD'
(: the value of this is correct, this is the same as the example, 3bfa292879f6447bbcda7001decf97f4a54dc650c8942174ae0a9121cf58ad04 :)
let $canonicalRequestHash := xdmp:sha256($canonicalRequest)
let $stringToSign :=
'AWS4-HMAC-SHA256
20130524T000000Z
20130524/us-east-1/s3/aws4_request
' ||
$canonicalRequestHash
let $dateKey := xdmp:hmac-sha256("AWS4wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "20130524")
let $regionKey := xdmp:hmac-sha256(binary { xs:hexBinary($dateKey) }, "us-east-1")
let $serviceKey := xdmp:hmac-sha256(binary { xs:hexBinary($regionKey) }, "s3")
let $signingKey := xdmp:hmac-sha256(binary { xs:hexBinary($serviceKey) }, "aws4_request")
return xdmp:hmac-sha256(binary { xs:hexBinary($signingKey) }, $stringToSign)

Related

I want to write the XQuery to print/iterate the keys and values in JSON

This is my sample JSON
{
"id":"743",
"groupName":"group1",
"transation":{
"101":"success",
"102":"rejected",
"301":"processing"
}
}
Expected Result:
"101":"success",
"102":"rejected",
"301":"processing"
Can anyone please help me to print the above result using for loop in XQuery?
If it's a JSON document, then you can use XPath and do things even easier:
(: read the doc (update to whatever URI) :)
let $json-doc := doc("/test.json")
for $node in $json-doc/transation/node()
return '"'||$node/name()||'":"'||$node||'"'
Or if you have a JSON string to parse to a JSON object, you can use the map:* functions to select and traverse the JSON object:
let $json-doc := xdmp:from-json-string('{ "id":"743", "groupName":"group1", "transation":{ "101":"success", "102":"rejected", "301":"processing" } }')
let $transation := map:get($json-doc, "transation")
for $key in map:keys($transation)
let $value := map:get($transation, $key)
return '"'||$key||'":"'||$value||'"'
If you wanted the JSON document from the database to be a JSON object to use the map functions, you can use the xdmp:from-json() function:
let $json-doc := doc("/test.json") => xdmp:from-json()
let $transation := map:get($json-doc, "transation")
for $key in map:keys($transation)
let $value := map:get($transation, $key)
return '"'||$key||'":"'||$value||'"'

Xquery. How to check current incremental backup status?

I have written an Xquery to that gets executed at the time of when incremental backup is in progress. I know the backup status returns three possible values -
completed, in-progress and failed. Not sure the exact value of last one but anyways this is my xquery -
xquery version "1.0-ml";
declare function local:escape-for-regex
( $arg as xs:string? ) as xs:string {
replace($arg,
'(\.|\[|\]|\\|\||\-|\^|\$|\?|\*|\+|\{|\}|\(|\))','\\$1')
} ;
declare function local:substring-before-last
( $arg as xs:string? ,
$delim as xs:string ) as xs:string {
if (matches($arg, local:escape-for-regex($delim)))
then replace($arg,
concat('^(.*)', local:escape-for-regex($delim),'.*'),
'$1')
else ''
} ;
let $server-info := doc("/config/server-info.xml")
let $content-database :="xyzzy"
let $backup-directory:=$server-info/configuration/server-info/backup-directory/text()
let $backup-latest-dateTime := xdmp:filesystem-directory(fn:concat( $backup-directory,'/',$content-database))/dir:entry[1]/dir:filename/text()
let $backup-latest-date := fn:substring-before($backup-latest-dateTime,"-")
let $backup-info := cts:search(/,cts:element-value-query(xs:QName("directory-name"),$backup-latest-date))
let $new-backup := if($backup-info)
then fn:false()
else fn:true()
let $db-bkp-status := if($new-backup)
then (xdmp:database-backup-status(())[./*:forest/*:backup-path[fn:contains(., $backup-latest-dateTime)]][./*:forest/*:incremental-backup eq "false"]/*:status)
else (xdmp:database-backup-status(())[./*:forest/*:backup-path[fn:contains(., $backup-latest-dateTime)]][./*:forest/*:incremental-backup eq "true"][./*:forest/*:incremental-backup-path[fn:contains(., fn:replace(local:substring-before-last(xs:string(fn:current-date()), "-"), "-", ""))]]/*:status)
return $db-bkp-status
We maintain a configuration file that stores backup status. If there is a new full backup day then $backup-info will return nothing. If it is daily incremental backup day then it will return the config. I'm using it just to check if todays backup is new full or incremental. For incremental day $backup-info is false and so it goes to the last line i.e. else condition. this doesn't return anything for incremental backups. Neither completed nor in-progress. I wonder how markLogic picks up the timestamp. Please assist on this.
Feel free to provide your own xquery from scratch. I can update mine.
I even took out the Job id and search in the output of the function xdmp:database-backup-status(()) but that job id too doesn't exist in the result set.
MarkLogic provides the Admin modules to provide much of the information you are attempting to get via other methods. The Admin UI modules (typically found in /opt/MarkLogic/Modules/MarkLogic/Admin/Lib) contains a lot of helpful code that can be adapted to get these sorts of details. In this case I would refer to database-status-form.xqy
define function db-mount-state(
$fstats as node()*,
$fcounts as node()*,
$dbid as xs:unsignedLong)
{
let $times := $fstats/fs:last-state-change,
$ls := max($times),
$since :=
if (not(empty($ls)))
then concat(" since ", longDate($ls), " ", longTimeSecs($ls))
else ""
return concat(database-status($dbid,$fstats,$fcounts),$since)
}
define function backup-recov-state($fstats as node()*)
{
if(empty($fstats/fs:backups/fs:backup)
and
empty($fstats/fs:restore))
then
"No backup or restore in progress"
else
if(empty($fstats/fs:backups/fs:backup))
then
"Restore in progress (see below for details)"
else
"Backup in progress (see below for details)"
}
... Call the functions against your database, then pull the details from the elements you want:
let $last-full-backup := max($fstats/fs:last-backup)
let $last-incremental-backup : = max($fstats/fs:last-incr-backup
return ($last-full-backup, $last-incremental-backup)
This is just some sample code snippets, not executable, but it should get you moving in the right direction.

How to pass multiple strings into a url in http get?

This is my current code:
var dek string = "dk"
resp,err := c.Get("https://google."VALUEHERE"")
What I want to be able to is pass different strings into my url if I need a bunch of different ones.
So ideally would be something like:
resp,err := c.Get("https://google.dk/value1=%v&value2=%v", value1, value2)
Is this possible in any way?
Use fmt.Sprintf(...) to build a string that does not require encoding:
hostname := fmt.Sprintf("google.%s", "dk")
// => "google.dk"
Use the net/url package to build URLs so they are encoded properly:
u := &url.URL{Scheme: "https", Host: hostname}
fmt.Println(u)
// => https://google.dk
q := u.Query()
q.Add("value1", "foo")
q.Add("value2", "Hello, World!")
u.RawQuery = q.Encode()
fmt.Println(u)
// => https://google.dk?value1=foo&value2=Hello%2C+World%21
resp, err := c.Get(u.String())
// ...

How to print specific fields from firebase database

I am a complete firebase newbie, but basically my situation is this I am collecting weather data and storing it in firebase like so:
{
"-Kw2H2dbJKZbbg-6LA6b": {
"date": "10/9/2017",
"data": "filler test data",
}
}
And then I will display this info to my website. I am using Go with firego as my backend and I am wondering how could I query my db and print any individual field. For example I wish to display the date
"date": "10/9/2017"
Just in general how can this be done. Any help is much appreciated!
If the query result is stored as map[string]interface{} then iterate over the results as:
//queryResults := ...
for _, val := range queryResults {
//test whether vmap is an object/not
vmap, ok := val.(map[string]interface{})
if !ok {
continue
}
//vmap contains {"date":..., "data":...}
field := "date"
if v, ok := vmap[field]; ok {
fmt.Printf("%s: %v\n", field, v)
}
}
If you don't know the object's hierarchy, you can implement a kind of find function to search for a specific key/field from queryResults. See https://stackoverflow.com/a/45757396/6207052.

Beego raw sql - Type conversion issue

Here is the code used inside the Beego MVC architecture.
var maps []orm.Params
//Pallets Completed already.
o.Raw("Select SUM(Things) as AllTheThings FROM SomeTable").Values(&maps)
numThings := strconv.Atoi(maps[0]["AllTheThings"].(string))
c.Data["Stuff"] = maps[0]["AllTheThings"]
Error:
multiple-value strconv.Atoi() in single-value context
Trying to figure out how I can get data out with our ORM and type cast it so arithmetic can be done on it.
Any more details please let me know.
strconv.Atoi has a signature of:
func Atoi(s string) (int, error)
you should check the error before using the result, like so:
var maps []orm.Params
//Pallets Completed already.
o.Raw("Select SUM(Things) as AllTheThings FROM SomeTable").Values(&maps)
numThings, err := strconv.Atoi(maps[0]["AllTheThings"].(string))
if err != nil {
// couldn't convert
}
c.Data["Stuff"] = maps[0]["AllTheThings"]

Resources