With Can You Keep A Secret, I could have optimized and added features indefinitely so at some point had to just publish it as it stood. Now that it’s live, I’ve had the time to make a few changes to this template which I didn’t get around to.
Row-level character sets
Each row of the table includes a new column Char Set, which stores a cache of
, any items which were already encrypted would experience some level of data corruption when you decrypted them. This affected every character that requiring adjustment because it was “out of bounds”.
Now, whenever an item is created, we cache the current character set into the Char Set column of that new row, then use that cache for any encryption and decryption operations.
It’s now safe to modify the available characters as the doc is in use!
Performance
In the previous doc, to convert between characters and numbers, we used a table
. For each character, we Filter() that table to find the row with the Charactercolumn matching our character, then grabbed that row’s Numbercolumn. This converted a string of letters into an array of numbers.
Old Method. Chars → Numbers:
Split("Secret", "")
.FormulaMap(
[Char Mapping]
.Filter(Character=CurrentValue)
.First()
.Number
)
Result 👉
294139544156
Split "Secret" into characters
Run through each character
Filter [Char Mapping] to find rows where the Character column matched our character
If multiple rows happen to match, just grab the first (this is not expected behavior, just a safe-guard)
Grab the Number of the row we find
To decrypt, we’d do the reverse - Filter() by the Numbercolumn, and return the Charactercolumn.
In this version of the doc, we use the new Char Set column instead. To map a character to a number, we use Find() which gives us that character’s position in the Char Set string. And to convert a number back to a character, we use Nth()which returns the array value at a given position.
New Method. Chars → Numbers:
Split("Secret", "")
.FormulaMap(
thisRow.[Char Set]
.Find(currentValue)
)
Result 👉
294139544156
New Method. Numbers → Chars:
WithName(
thisRow.[Char Set].Split(""),
CharArray,
List()
.FormulaMap(
CharArray.Nth(currentValue)
)
)
Result 👉
z"—/";
Split "Secret" into characters
Run through each character
Find the position of each character in the string stored in Char Set column.
WithName stores the result of a formula as a named variable.
Here we Split() the Char Set column into individual characters
... and store that as "CharArray"
Using our list of numbers,
let's run through them one by one
And grab the character that's in CharArray at that position
After days of tests, I was finally confident that the new method worked and was stable. At the 11th hour, however, I remembered that text inputs can’t store line break characters. :(
Because we’re caching our character mapping as a string in a text input (canvas control TEXT Char Mapping Cache on the
page), this “update” caused the doc to no longer support line-breaks in user’s text. Because the character couldn’t exist within that canvas control, all line breaks would just be dropped from any text the user enters.
Additionally, when caching the Character Mapping table into the text input, the line break was getting imported as a second “space” character. This caused a few corruption issues that I’d noticed but struggled to replicate.
It’s unnerving how much work it took to restore line breaks, but after a very long afternoon and a grumpy partner, I managed to get an update to work.
So please, use as many line breaks as possible!!!
Forms to skip Row Activity and Version History
By building the system this way, it’s not necessary to ever store the password, so we don’t incur the risk of needing to protect it. Although
can be helpful tools to keep users from accessing parts of your doc, it’s important to remember these are user interface features, not security features
Anyone with sufficient technical expertise and with access to the Doc can work around these features. By contrast, this template allows you to store information encrypted at rest so that even if the absolute worst breach happened, all your docs were breached, and an extremely malicious and motivate user
The final piece of the puzzle is that we use Forms to create items and to decrypt them for viewing later on. Forms provide a temporary volatile state - a bubble that insulates the user’s unencrypted text and their password from the rest of the doc. This means users can type in sensitive information, safe in the knowledge that information will never be synced to Coda’s servers, stored in a table, or be visible to any other user until that information has been encrypted fully first.
More detail’s available by clicking the gray info buttons on