{ "kind": "open-flow-workflow", "version": 1, "name": "Publish a Message to an SNS Topic", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_b09aaf7e101bd936": { "name": "Start", "kind": "start", "inputDefs": [] }, "n_3f4217beafc0e7c5": { "inputs": { "topicArn": { "kind": "value", "value": "YOUR_SNS_TOPIC_ARN" }, "message": { "kind": "value", "value": "This is a test message" }, "subject": { "kind": "value", "value": "This is a test subject" }, "accessKeyId": { "kind": "unset" }, "secretAccessKey": { "kind": "unset" }, "sessionToken": { "kind": "value", "value": null } }, "name": "Prepare and sign SNS request", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "topicArn" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "message" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "subject" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "accessKeyId" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "secretAccessKey" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "sessionToken" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "authorization" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "amzDate" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "body" } ], "name": "Prepare and sign SNS request", "moduleId": "n_1d02e96c959b0fc0", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_33507bc0006d0010": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_3f4217beafc0e7c5", "output": "url" } ] }, "header.Content-Type": { "kind": "value", "value": "application/x-www-form-urlencoded" }, "header.Authorization": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_3f4217beafc0e7c5", "output": "authorization" } ] }, "header.X-Amz-Date": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_3f4217beafc0e7c5", "output": "amzDate" } ] }, "header.X-Amz-Security-Token": { "kind": "value", "value": null }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_3f4217beafc0e7c5", "output": "body" } ] } }, "name": "Publish to SNS", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "header.Content-Type" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "header.Authorization" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "header.X-Amz-Date" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "header.X-Amz-Security-Token" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "body" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Publish to SNS", "executor": { "method": "POST", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [ "Content-Type", "Authorization", "X-Amz-Date", "X-Amz-Security-Token" ] }, "bodyFormat": "text", "authentication": { "type": "none" }, "responseFormat": "text", "statusPolicy": "success", "kind": "http-request" } } }, "n_3bf050df3cf32cad": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_33507bc0006d0010", "output": "body" } ] } }, "name": "Read the message ID", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "body" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "messageId" } ], "name": "Read the message ID", "moduleId": "n_c77f221ff7402325", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_4320a1b425691d41": { "name": "Published message", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "messageId" } ], "outputMappings": { "messageId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_3bf050df3cf32cad", "output": "messageId" } ] } } } }, "edges": [ { "source": "n_b09aaf7e101bd936", "target": "n_3f4217beafc0e7c5" }, { "source": "n_3f4217beafc0e7c5", "target": "n_33507bc0006d0010" }, { "source": "n_33507bc0006d0010", "target": "n_3bf050df3cf32cad" }, { "source": "n_3bf050df3cf32cad", "target": "n_4320a1b425691d41" } ] } }, "modules": { "n_1d02e96c959b0fc0": { "name": "Prepare and sign SNS request", "imports": [], "source": "import{createHash,createHmac}from'node:crypto';export default function sign({topicArn,message,subject,accessKeyId,secretAccessKey,sessionToken}){if(typeof topicArn!=='string')throw Error('Configure SNS topic ARN');const m=/^arn:(aws|aws-us-gov|aws-cn):sns:([a-z0-9-]+):([0-9]{12}):([A-Za-z0-9_-]{1,256})$/.exec(topicArn);if(!m)throw Error('Configure a standard SNS topic ARN');if(typeof message!=='string'||!message||typeof subject!=='string'||!subject||subject.length>=100||/[\\x00-\\x1f\\x7f]/.test(subject))throw Error('Enter a message and a subject under 100 characters without line breaks');if(typeof accessKeyId!=='string'||!accessKeyId.trim()||typeof secretAccessKey!=='string'||!secretAccessKey.trim())throw Error('Configure AWS credentials');if(sessionToken!=null&&typeof sessionToken!=='string')throw Error('Invalid session token');const region=m[2],host='sns.'+region+'.amazonaws.com'+(m[1]==='aws-cn'?'.cn':''),body='Action=Publish&Version=2010-03-31&Message='+encodeURIComponent(message)+'&TopicArn='+encodeURIComponent(topicArn)+'&Subject='+encodeURIComponent(subject),timestamp=new Date().toISOString().replace(/[:-]|\\.\\d{3}/g,''),date=timestamp.slice(0,8),headers={'content-type':'application/x-www-form-urlencoded',host,'x-amz-date':timestamp,...(sessionToken?{'x-amz-security-token':sessionToken}:{})},names=Object.keys(headers).sort(),signed=names.join(';'),canonicalHeaders=names.map(n=>n+':'+headers[n].trim().replace(/\\s+/g,' ')+'\\n').join(''),hash=x=>createHash('sha256').update(x).digest('hex'),hmac=(k,x)=>createHmac('sha256',k).update(x).digest(),scope=date+'/'+region+'/sns/aws4_request',canonical=['POST','/','',canonicalHeaders,signed,hash(body)].join('\\n'),tosign=['AWS4-HMAC-SHA256',timestamp,scope,hash(canonical)].join('\\n'),key=hmac(hmac(hmac(hmac('AWS4'+secretAccessKey,date),region),'sns'),'aws4_request'),signature=createHmac('sha256',key).update(tosign).digest('hex');delete headers.host;headers.authorization='AWS4-HMAC-SHA256 Credential='+accessKeyId+'/'+scope+', SignedHeaders='+signed+', Signature='+signature;return{url:'https://'+host+'/',body,authorization:headers.authorization,amzDate:timestamp}}\n" }, "n_c77f221ff7402325": { "name": "Read the message ID", "imports": [], "source": "export default function result({body}){if(typeof body!=='string')throw Error('SNS did not return XML');const m=/<(?:[A-Za-z_][\\w.-]*:)?MessageId>\\s*([A-Za-z0-9-]+)\\s*<\\/(?:[A-Za-z_][\\w.-]*:)?MessageId>/.exec(body);if(!m)throw Error('SNS did not confirm a message ID');return{messageId:m[1]}}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }