Skip to content

Instantly share code, notes, and snippets.

@alopresto
Created February 11, 2019 19:56
Show Gist options
  • Save alopresto/a8af4cd4f6b37df55e4ab004428fb83a to your computer and use it in GitHub Desktop.
Save alopresto/a8af4cd4f6b37df55e4ab004428fb83a to your computer and use it in GitHub Desktop.
Very simplistic magnetic stripe track 1 & 2 parsing logic in Groovy. Extracts example fields and writes to JSON output.
import groovy.json.JsonBuilder
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import org.apache.commons.io.IOUtils
import org.apache.nifi.processor.io.StreamCallback
import java.nio.charset.StandardCharsets
def flowFile = session.get()
if (flowFile == null) {
return
}
final String CC_PATTERN = /^%B\d{16}\^[A-Za-z]+/
final String PC_PATTERN = /^%1\w+/
final String PP_PATTERN = /^%PP\/\/\w+/
final String SBUX_PATTERN = /^%B601.*SERVICERECOVERY/
String determinedType = "unknown"
flowFile = session.write(flowFile, { inputStream, outputStream ->
def content = IOUtils.toString(inputStream, StandardCharsets.UTF_8)
Map parsedObject
// Logic to do various parsing
if (content =~ CC_PATTERN) {
log.info("Detected CC format")
parsedObject = parse(content, "CC")
} else if (content =~ PP_PATTERN) {
log.info("Detected Priority Pass format")
parsedObject = parse(content, "PP")
} else if (content =~ PC_PATTERN) {
log.info("Detected Players Club format")
parsedObject = parse(content, "PC")
} else if (content =~ SBUX_PATTERN) {
log.info("Detected Starbucks Gift Card format")
parsedObject = parse(content, "SB")
} else {
log.info("Could not determine MSR type; using generic parsing heuristics")
parsedObject = parse(content, "generic")
}
// Write the determined type to an attribute
determinedType = parsedObject["type"]
// Write the timing info to the parsed object
parsedObject["time_parsed"] = new Date().format('YYYY-MM-dd_HH-mm-ss.SSS Z')
parsedObject["id"] = flowFile.uuid
parsedObject["source"] = flowFile.filename
// Convert the object into JSON
def jsonString = JsonOutput.toJson(parsedObject)
log.info("Formed JSON: ${jsonString}")
outputStream.write(jsonString.getBytes(StandardCharsets.UTF_8))
} as StreamCallback)
flowFile.determinedType = determinedType
private Map parse(String content, String detectedType) {
Map parsedObject = [:]
parsedObject["type"] = detectedType
def tracks = content.split(/\?\n;/)
log.info("Tracks (${tracks.size()}): ${tracks.collect { "\n\t${it}" }}")
// Put the track 1 data directly
parsedObject["track1"] = tracks[0]
def track1Elements = tracks[0].split(/\^/)
log.info("Track 1 Elements (${track1Elements.size()}): ${track1Elements.collect { "\n\t${it}" }}")
// The PAN and Name are common elements
parsedObject["pan"] = track1Elements[0][2..-1] // Skip the start sentinel and format code (%B)
if (track1Elements.size() > 1) {
parsedObject["name"] = track1Elements[1].trim()
}
if (track1Elements.size() > 2) {
// Put the remaining track 1 data in a generic field
parsedObject["additionalTrack1"] = track1Elements[2..-1].join("^")
}
// Put track 2 data directly
parsedObject["track2"] = tracks[1]
// Return the parsed object
parsedObject
}
session.transfer(flowFile, REL_SUCCESS)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment