Appian Community and Appian Academy are being upgraded. As a part of the upgrade, Appian Community is currently in read-only mode, and user registration is disabled until August 3. We apologize for any inconvenience this may cause, but a more secure, stable, and performant Community experience is coming soon!

The new Appian Community launches August 3, followed by Appian Academy on August 7. During the migration, Appian Community Edition, Appian Academy, Documentation, Certifications, Instructor-led Customer Training, Partner Sales Training & Accreditation, and Forum (for Appian Partners and Customers only) will remain available.

How to generate base64 digest string in Appian.

Certified Senior Developer

Hello All,

Below is the code snippet from Ruby.

Digest::SHA256.base64digest('')

I need to generate the same in Appian and pass it to the integration header parameter, please let me know if anyone has done this before.

Thank You,

Sneha.

  Discussion posts and replies are publicly visible

Parents Reply Children
  • 0
    Certified Lead Developer
    in reply to lalithap4822
    failing to decode Euro symbol

    Are you talking about the "â" character?  Because that's what it looks like your example string contains.  I'm unclear but for some reason my base64 back-parser is interpreting it as 2 characters instead of 1, which I'll look into - it could be an error in my parser, or some weird exception involving the convergence of character sets or something, i'm not terribly sure yet.

  • +2
    Certified Lead Developer
    in reply to lalithap4822

    After some further research, I found that extended characters (anything past char(127)) are handled specially in standard UTF-8 base64 encoding.  I did a little tampering with my existing rules and came up with the following updates today:

    Encoder:

    /* encode */
    a!localVariables(
      local!text: ri!text,
    
      local!charset: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
      local!codeArray: code(local!text),
      local!binArray: a!forEach(
        local!codeArray,
        if(
          fv!item > 127,
          if(
            fv!item > 2047,
            if(
              fv!item > 65535,
              dec2bin(fv!item, 21),
              dec2bin(fv!item, 16)
            ),
            dec2bin(fv!item, 11)
          ),
          dec2bin(fv!item, 8)
        )
      ),
      
      local!preProcessBinArray: a!forEach(
        /* encoding UTF-8 self-synchronizing (grumble) ref: https://en.wikipedia.org/wiki/UTF-8#Description */
        items: local!binArray,
        expression: a!match(
          value: len(fv!item), default: fv!item,
          
          equals: 8,
          then: fv!item,
          
          equals: 11,
          then: {
            concat( "110", left(fv!item, 5) ),
            concat( "10", right(fv!item, 6) )
          },
          
          equals: 16,
          then: {
            concat( "1110", left(fv!item, 4) ),
            concat( "10", mid(fv!item, 5, 6) ),
            concat( "10", right(fv!item, 6) )
          },
          
          equals: 21,
          then: {
            concat( "11110", left(fv!item, 3) ),
            concat( "10", mid(fv!item, 4, 6) ),
            concat( "10", mid(fv!item, 10, 6) ),
            concat( "10", right(fv!item, 6) )
          }
        )
      ),
      
      local!bins: concat(local!preProcessBinArray),
      
      local!groupedBins: split(concat(
        a!forEach(
          items: code(local!bins), 
          expression: char(fv!item) & if(and(mod(fv!index, 6) = 0, not(fv!isLast)), "-=-=-", "")
        )
      ), "-=-=-" ),
      local!lastBin: index(local!groupedBins, length(local!groupedBins)),
      local!padding: a!match(
        value: len(local!lastBin),
        equals: 2, then: "==",
        equals: 4, then: "=",
        equals: 6, then: "",
        default: "error condition"
      ),
      local!bindexes: a!forEach(
        items: local!groupedBins,
        expression: if(
          fv!isLast,
          bin2dec(substitute(padright(fv!item, 6), " ", "0")),
          bin2dec(fv!item)
        )
      ) + 1,
    
      local!assembledOutput: concat(a!forEach(items: local!bindexes, expression: charat(local!charset, fv!item))) & local!padding,
    
      local!assembledOutput
    )

    Decoder:

    /* decode */
    a!localVariables(
      local!base64text: ri!base64text,
    
      local!charset: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
    
      local!charCodes: code(local!base64text),
      /*local!paddingCount: count(wherecontains(code("="), local!charCodes)),*/
      local!unpaddedChars: a!flatten(a!forEach(
        items: local!charCodes,
        expression: if(fv!item = code("="), {}, find(char(fv!item), local!charset)-1)
      )),
      local!rawBins: dec2bin(tointeger(local!unpaddedChars), 6),
    
      local!decodedBins: split(
        concat(
          a!forEach(
            items: code(concat(local!rawBins)),
            expression: if(
              mod(fv!index, 8) = 0,
              char(fv!item) & "-=-=-",
              char(fv!item)
            )
          )
        ),
        "-=-=-"
      ),
    
      
      local!intermediaryDecodedBinList: a!flatten(a!forEach(
        /* update to handle UTF-8 self-synchronizing for extended character-set items. ref: https://en.wikipedia.org/wiki/UTF-8#Description */
        items: local!decodedBins,
        expression: if(
          or(fv!item = "0000", fv!item = "00"),
          {},
          
          a!match(
            value: fv!item, default: fv!value,
    
            /* handle 2-byte items */
            whentrue: left(fv!value, 3) = "110",
            then: concat(right(fv!item, 5), right(local!decodedBins[fv!index+1], 6)),
            whenTrue: or(  /* manually check and skip re-using subsequent ones on following iterations (ugh) */
              and(fv!index >= 2, left(local!decodedBins[fv!index-1], 3) = "110"),
            ),
            then: {},
    
            /* handle 3-byte items */
            whentrue: left(fv!value, 4) = "1110",
            then: concat(right(fv!item, 4), right(local!decodedBins[fv!index+1], 6), right(local!decodedBins[fv!index+2], 6)),
            whenTrue: or(  /* manually check and skip re-using subsequent ones on following iterations (ugh) */
              and(fv!index >= 2, left(local!decodedBins[fv!index-1], 4) = "1110"),
              and(fv!index >= 3, left(local!decodedBins[fv!index-2], 4) = "1110")
            ),
            then: {},
    
            /* handle 4-byte items */
            whentrue: left(fv!value, 5) = "11110",
            then: concat(right(fv!item, 3), right(local!decodedBins[fv!index+1], 6), right(local!decodedBins[fv!index+2], 6), right(local!decodedBins[fv!index+3], 6)),
            whenTrue: or(  /* manually check and skip re-using subsequent ones on following iterations (ugh) */
              and(fv!index >= 2, left(local!decodedBins[fv!index-1], 5) = "11110"),
              and(fv!index >= 3, left(local!decodedBins[fv!index-2], 5) = "11110"),
              and(fv!index >= 4, left(local!decodedBins[fv!index-3], 5) = "11110")
            ),
            then: {}
            
          )
        )
      )),
      
      concat(
        a!forEach(
          local!intermediaryDecodedBinList,
          char(bin2dec(fv!item))
        )
      )
    )

    These work with text containing the euro symbol and other extended character set items to an extent.  Warning that I have *not* tested them very thoroughly for corner cases (like items that exist at character set boundaries) yet, but the results so far match results given by public online base64 encoder tools.

  • 0
    Certified Associate Developer
    in reply to Mike Schmitt

    Thanks Mike this worked.