hackforla / 311-data

Empowering Neighborhood Associations to improve the analysis of their initiatives using 311 data
https://hackforla.github.io/311-data/
GNU General Public License v3.0
62 stars 63 forks source link

Update contact form to use frontend-only services #1682

Closed traycn closed 3 months ago

traycn commented 8 months ago

Overview

We need to update the contact form to use front-end only services for 311-Data users to submit their concerns as a github issue. Users would then receive a confirmation email.

Action Items

Resources/Instructions

Octokit

Octokit/Core.js documentation Octokit/Core.js package Create a new Github Access Token Create a new issue - Octokit documentation

EmailJS

Sign-Up for EmailJS Send an email after Contact Form is submitted

Other Details

For reference to the data we are using, the values collected on the forms submit are below.

// Contact Form field values:
{
     FirstName,
     LastName,
     Email,
     Association (optional),
     Message
}

Create a Github Issue using Octokit/Core.js

Example POST body data model (open to change)

{
    owner: 'hackforla',
    repo: '311-data',
    title: 'Contact Form - {FirstName} {LastName} {Association}',
    body: '{FirstName, ` `, LastName,` `, Association} <br>
             Email - {Email} <br>
             Message - {Message}
          ',
    assignees: [
      '[insert default assignee here]'
    ],
    milestone: [insert default milestone here],
    labels: [
      'bug'
    ],
    headers: {
      'X-GitHub-Api-Version': '2022-11-28'
    }
}

Dependency

ryanfchase commented 8 months ago

This ticket is ready to be picked up, thank you @traycn

ryanfchase commented 5 months ago

I'm going to jot a ChatGPT response that I generated when I asked about measures we can take to secure our access tokens. I think this is relevant for all tokens we use, considering we don't have a backend:

cc @Skydodle

Token Security Strategies

Certainly! Without a backend server, you have to rely on alternative methods to secure your access token. Here's how you can adapt the suggestions: - Environment Variables: Since you don't have a backend server to store environment variables, you can't directly use this approach. Instead, consider storing the access token securely in your frontend code. Use techniques like encryption or obfuscation to make it more difficult for users to extract the token from your code. - Token Scope: When generating the access token, ensure that you only grant it the permissions necessary for the specific actions it needs to perform. Avoid granting excessive permissions that could potentially be misused if the token is compromised. - Client-side Proxy: Implement a client-side proxy using serverless functions or cloud services. For example, you can use AWS Lambda or Azure Functions to create lightweight proxy functions that make requests to GitHub's API on behalf of your frontend application. These functions can securely handle the access token and enforce access control policies. - Request Validation: Even though you don't have a backend server, you can still implement some level of request validation on the client-side. Validate requests to ensure they meet certain criteria before making API calls. This can include checking for required parameters, sanitizing input, and verifying the integrity of the request. - Token Rotation: Although you can't rotate access tokens as easily without a backend server, you can manually regenerate and update the token in your frontend code when necessary. Make sure to follow best practices for securely storing and updating the token. - Token Expiry: Set an expiry time for the access token and handle token expiration gracefully in your frontend code. When the token expires, prompt the user to reauthenticate or automatically refresh the token if possible. Regarding token swapping strategies when a token is suspected to be misused: - Monitoring and Logging: Implement client-side logging and monitoring to track API usage and detect any suspicious activity associated with the access token. Monitor network requests, error logs, and other relevant metrics to identify potential security threats. - Token Revocation: If you suspect that a token has been compromised, manually revoke the token through GitHub's interface. Update your frontend code to use a new token and consider implementing additional security measures to prevent similar incidents in the future. - Token Blacklisting: Maintain a blacklist of revoked or compromised tokens locally in your frontend code. Update your application to reject requests using blacklisted tokens and notify users of the security incident. - User Notifications: Notify users of any suspicious activity detected in their account or associated with their access token. Provide clear instructions on how to secure their account and mitigate potential risks. By adapting these strategies to your frontend-only architecture, you can still enhance the security of your access tokens and protect your resources from unauthorized access.

Skydodle commented 5 months ago

Hello, I've been thinking about a different approach using AWS Lambda that might be worth considering.

High Level Overview

  1. Front-End Setup: When contact form is submitted, it makes a POST request to the serverless function URL (which is the Lambda function below).
  2. Lambda Serverless Function:
    • The function receives the form data, proces it and prepare it for submission to Github.
    • Script to interact with Github API. Authenticate with our Github access token and post the new issue to our Github repo.

Detail on AWS Lambda Implementation:

  1. Lambda Function Setup:
    • No Need for writing up a server: Log into AWS account and create a new Lambda function with JavaScript, then write a simple JavaScript handler that tells Lambda how to execute when we receive the HTTP request from the contact form.
    • API Gateway: Set up an API Gateway that acts as the front door for requests to trigger the Lambda function. When the contact form make a POST request to a URL provided by the API Gateway, which then invokes the Lambda function. Setting up the API Gateway does not require any coding at all, it's simply choosing configurations via the AWS platform.
  2. Function Logic (the only coding part):
    • Handle Request: The Lambda function receives the form data as a JSON payload, processes it as needed (validation, sanitization, restructuring the data etc.), and then prepares it for GitHub.
    • Create Github Issue: The Lambda function uses the GitHub API to create an issue in our repository. It would authenticate with GitHub using an access token and use the GitHub API to post the new issue.
      1. Secure Token:
        • Use AWS Secrets Manager or Environment Variables in the Lambda configuration to store sensitive information like GitHub access tokens securely.
        • Configure the neccesary IAM roles and permission for access to Lambda function and its interactions.

PROS

CONS

Final Thoughts

In my opinion, AWS Lambda would be a quick and simple setup as most steps are take care of by AWS automations. However, my opinion is definitely biased since I had some exposure with AWS. I'm happy to hear other options or dicuss any possible issues with this route.

Skydodle commented 5 months ago

@ryanfchase

There is also one major issue regardless of how we end up implementing this. We need to generate an access token in order to post a Github issue from whatever implementation we chose. I checked around for organizational permissions, and I think only Bonnie and Chelsea can generate access tokens. This might be something we have to bring up to Bonnie to see what to do best.

Skydodle commented 4 months ago

ETA: Sunday 6/16 Availability: M-Sun after 6pm

Skydodle commented 4 months ago

@ryanfchase

For the Personal Access Token, I would suggest to set it as no expiration, with the following scopes:

Mandatory:

Optional Add-Ons For Future Functionality Expansion

ryanfchase commented 4 months ago

@Skydodle I need to have the admin team create a bot account for us in order to automate the opening of issues.

Here's my references to how the website team is utilizing a bot in a smiliar capacity:

In the meantime, please develop with your own access token.

ryanfchase commented 4 months ago

Assigning myself while I create the emailjs deliverables ETA 6-8-24 Availability: weekends before 7p

ryanfchase commented 4 months ago

The EmailJS service has been set up within the 311-DataDev vault in 1Password.

I'm also opening a ticket on the PM team (and possibly UIUX team) to take a pass at the contents of the page: https://github.com/hackforla/311-data/issues/1754

ryanfchase commented 4 months ago

@Skydodle I know you're sick so take your time. When you can, please provide an update on this ticket and an ETA of when you believe it will be complete.

Skydodle commented 4 months ago

ETA: Friday 6/21 EOD Avaialbility: Friday to Monday after 5pm

ryanfchase commented 4 months ago

I'm realizing that to fully complete this ticket, I think this will become dependent on one other ticket:

I was thinking that maybe it would also be dependent on the email template we are designing... but I think if we provide the css to the emailJS template on our account, @Skydodle's code is agnostic to how the email's formatting and inner contents.

In any case, @Skydodle let me know when you hit a point where you are fully blocked by #1769 -- and I will move this ticket to Icebox and list its dependency.

Skydodle commented 4 months ago

Leaving note regarding the personal access token required for the octokit service. Currently for local development purpose, I created my own Github PAT. The PM team will need to create a HFLA bot account with its own PAT to use for the app in production.

For your reference, the scopes I chose when creating the PAT were repo, workflow, and notification.

Skydodle commented 4 months ago

Overview

Did some testing for security, and found that our idea of directly using Octokit from client to create Github issue without a server is highly insecure. Even if we stored the Github Personal Access Token (PAT) in Github Secrets for production, at build time any process.env reference will be replace with the actual API keys. These keys can be exposed to anyone who inspect the JS code running in the browser.

I inspected our live site with Chrome Dev Tools and search for our Mapbox API token, and indeed it was easily found. See screenshot below, last line contains Mapbox access token:

Screenshot

Screenshot 2024-06-19 at 8 13 07 AM

The Mapbox API key is for public usage on Mapbox, which doesnt have any effect on our Github if stolen. The Github PAT however, if exposed can pose a serious security threat to our organization.


Options

1. Create a Google Form

2. Open Google Apps Script

3. Write the Google Apps Script

function createTrigger() { var form = FormApp.openById("YOUR_FORM_ID"); ScriptApp.newTrigger("onFormSubmit") .forForm(form) .onFormSubmit() .create(); }



</p>
</details>

- Note: Need a Google account for our team if not already have one, and need to ensure access to the Google Apps Script project is restricted to trusted users.

---

### Considerations
@ryanfchase I understand you want to go with option 2 to keep the application "frontend only". In my opinion, both options does the same thing. They both require the client to send a request to an outside server: 
   - In Option 1, the current contact form hits the Netlify service we created
   - In Option 2, the Google Form hits the Google Apps Scripts API.

Both options has the benefit of storing the PAT token securely outside of our client code base.

The major difference we need to consider is the frontend design we intend to present to the users, which we should open up for discussion with design team and maybe research team:
   - Option 1 will use the existing contact form we have on the Contact page
   - Option 2 will either:
      - Embed the Google Form on the Contact page OR
      - Some other design that integrate the Google Form, something maybe the design team can come up with
   - Team to discuss which form would be user-centric on design, usability, and styling consistence with the rest of the app, etc.
ryanfchase commented 4 months ago

Hi @Skydodle,

Please leave a comment with the following items:

Skydodle commented 4 months ago

Updated ETA: Friday 6/28 Avaialbility: Friday to Monday after 5pm

Skydodle commented 3 months ago

Closing this ticket as we are taking a different implementation from this issue's approach. The original proposal exposes the access token without a server to store it. This ticket is replaced with #1780.

ryanfchase commented 3 months ago

Modifying as Not Planned due to technical limitations