mohd-faraz

_blogs

// blogs / 20260721.md

Dev Log: July 21 Wrap-up

2026-07-21
#frontend#security#workflow-engine#refactoring

Overview

Today was a bit of a mixed bag. I spent the first half of the day wrestling with some UI polish for our chat widget, and the second half diving into some security refactoring for the login flow and workflow execution logic. It felt like a solid day of "cleaning house" while shipping some necessary functional updates.

What I Worked On

Making the chat embed feel less cramped

The chat widget was feeling a bit claustrophobic in its original size. I bumped up the window dimensions and added some smoother transitions for when the panel opens and closes. Previously, it just kind of popped into existence, which felt a bit jarring. Now, it feels a lot more integrated into the user's workflow. I also spent a minute or two cleaning up the header actions and the voice settings toggle to make sure everything looks aligned.

Hardening the login flow

One of the bigger tasks was updating how we handle user data during the login process. We're moving away from passing certain identifiers in plain text. I implemented a new decryption layer in the login service. Now, when the app initializes, it takes encrypted payloads for things like session IDs and user roles and decodes them on the fly using a key provided in the response metadata.

It’s a bit more overhead on the client side, but it’s a massive improvement for security. Here’s the gist of how I’m handling that data transformation now:

// Generalizing the decryption logic for sensitive login fields
decryptLoginInfo(data) {
  if (data.resource && data.resource.length > 0) {
    const meta = data.resource[0].meta_info;
    const key = meta?.secret_key;
    
    // If we have the key, decrypt the sensitive bits
    if (key) {
      return {
        ...data.resource[0],
        session_id: this.crypto.decrypt(key, data.resource[0].session_id),
        user_id: this.crypto.decrypt(key, data.resource[0].user_id)
      };
    }
  }
  return data;
}

Cleaning up the Workflow Executor

On the backend side, I spent some time with the workflow execution engine. One pain point we had was that it was hard to reference specific nodes by their human-readable names during execution. I updated the input builder to expose nodeNames.

The tricky part was ensuring those names didn't break anything if a user used spaces or weird symbols. I added a small regex step to sanitize the names into valid keys. It’s a small change, but it makes the data flow much easier to debug when you're looking at a large execution trace.

# Sanitizing node names to ensure they work as keys in the input map
source_name = node_data.get("node_name")
if source_name:
    # Replace non-alphanumeric chars with underscores
    sanitized = re.sub(r'[^a-zA-Z0-9_]', '_', str(source_name).strip())
    sanitized = re.sub(r'_+', '_', sanitized) # Remove double underscores
    if sanitized:
        inputs[sanitized] = result_payload

Small Wins & Config Tweaks

I also decided to lift the restriction on the httpRequest node for embedded users. We previously had it blocked in the environment config, but the use case for it has grown enough that it didn't make sense to keep it locked down.

Wrapping Up

Finished the day with some general linting and formatting in the LoginService. It’s one of those files that everyone touches but nobody formats, so it felt good to leave it a little cleaner than I found it. Tomorrow, I'll probably be diving deeper into the workflow engine to see if there are any other bottlenecks in how we map node dependencies. See ya then.