Initial commit: Multi-state Flock public records toolkit
- Interactive request generator with 20 state support - Quick state law lookup tool - Security-hardened input validation - Copy-paste templates for non-technical users - MIT licensed civic tech project
This commit is contained in:
commit
2095cb1951
6 changed files with 1308 additions and 0 deletions
60
.gitignore
vendored
Normal file
60
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# Generated request files
|
||||
foia_request_*.txt
|
||||
flock_request_*.txt
|
||||
|
||||
# Node modules (if anyone adds dependencies)
|
||||
node_modules/
|
||||
.pnpm-store/
|
||||
|
||||
# Environment variables (shouldn't be here, but just in case)
|
||||
.env
|
||||
.env.local
|
||||
.env.production
|
||||
.env.development
|
||||
|
||||
# Personal information
|
||||
personal_info.json
|
||||
my_request.txt
|
||||
|
||||
# IDE / Editor
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.DS_Store
|
||||
|
||||
# Build outputs
|
||||
dist/
|
||||
build/
|
||||
*.js.map
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Testing
|
||||
coverage/
|
||||
.nyc_output/
|
||||
|
||||
# Temporary files
|
||||
tmp/
|
||||
temp/
|
||||
*.tmp
|
||||
|
||||
# OS files
|
||||
Thumbs.db
|
||||
.DS_Store
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
|
||||
# Backup files
|
||||
*.bak
|
||||
*.backup
|
||||
*_backup
|
||||
|
||||
# Documentation (local only)
|
||||
SECURITY-AUDIT-SUMMARY.md
|
||||
RELATIONSHIP-TO-ROSSMANN-GUIDE.md
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2025 Denver Flock Opposition Community
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
322
README.md
Normal file
322
README.md
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
# Flock Safety Public Records Request Tools
|
||||
|
||||
Tools to help citizens exercise their legal right to request public records about Flock Safety surveillance systems in their communities.
|
||||
|
||||
## 🎯 Purpose
|
||||
|
||||
Government surveillance systems should be transparent and accountable to the communities they serve. This project makes it easier for citizens to request public information about Flock Safety automated license plate reader (ALPR) cameras using proper legal citations for each state.
|
||||
|
||||
## ⚡ Quick Start
|
||||
|
||||
### For Tech-Savvy Users (Command Line)
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/YOUR_USERNAME/flock-public-records-toolkit
|
||||
cd flock-public-records-tools
|
||||
|
||||
# Quick lookup: What's my state's law?
|
||||
bun lookup-state-law.ts CO
|
||||
|
||||
# Run the interactive generator
|
||||
bun generate-flock-request.ts
|
||||
|
||||
# Follow the prompts to generate your request
|
||||
```
|
||||
|
||||
### For Everyone (Copy-Paste Template)
|
||||
|
||||
If you're not comfortable with command-line tools:
|
||||
|
||||
1. Open `flock_request_template.md`
|
||||
2. Find your state's legal citations in the reference section
|
||||
3. Copy the template and fill in your information
|
||||
4. Send to your local agency
|
||||
|
||||
### Coming Soon: Web Form
|
||||
|
||||
We're building a simple web-based version that works in any browser - no installation needed!
|
||||
|
||||
---
|
||||
|
||||
## 📂 What's Included
|
||||
|
||||
### Interactive Scripts
|
||||
|
||||
**`lookup-state-law.ts`** (Quick Reference) ⚡
|
||||
- Instant state statute lookup
|
||||
- Shows correct legal citations for your state
|
||||
- No installation needed - just run it
|
||||
- Usage: `bun lookup-state-law.ts <STATE_CODE>`
|
||||
|
||||
**`generate-flock-request.ts`** (Interactive Generator) 🔒
|
||||
- Security-hardened with input validation
|
||||
- Prevents path traversal and injection attacks
|
||||
- Validates email addresses and ZIP codes
|
||||
- Generates state-specific requests
|
||||
- Safe for public use
|
||||
|
||||
### Templates & Documentation
|
||||
|
||||
**`flock_request_template.md`**
|
||||
- Copy-paste ready template
|
||||
- State-by-state legal reference guide
|
||||
- Best practices and tips for success
|
||||
|
||||
**`foia_req_raw.md`**
|
||||
- Original template with errors (kept for reference)
|
||||
- ⚠️ DO NOT USE - contains legal errors
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Critical Issues with Original Template
|
||||
|
||||
The original template had several legal errors that could undermine requests:
|
||||
|
||||
❌ **Incorrect terminology**: States don't use "FOIA" - that's federal only
|
||||
❌ **Wrong statute citation**: Referenced non-existent statute
|
||||
❌ **Incorrect response time**: Claimed universal 10-day deadline (varies by state)
|
||||
❌ **Missing 30-day urgency**: Flock deletes data after 30 days
|
||||
|
||||
**Our tools fix all of these issues.**
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ State Coverage
|
||||
|
||||
Currently supports **20 states** with accurate legal citations:
|
||||
|
||||
- Arizona (AZ)
|
||||
- California (CA)
|
||||
- Colorado (CO)
|
||||
- Florida (FL)
|
||||
- Georgia (GA)
|
||||
- Illinois (IL)
|
||||
- Massachusetts (MA)
|
||||
- Maryland (MD)
|
||||
- Michigan (MI)
|
||||
- Nevada (NV)
|
||||
- New Mexico (NM)
|
||||
- New York (NY)
|
||||
- North Carolina (NC)
|
||||
- Ohio (OH)
|
||||
- Oregon (OR)
|
||||
- Pennsylvania (PA)
|
||||
- Tennessee (TN)
|
||||
- Texas (TX)
|
||||
- Virginia (VA)
|
||||
- Washington (WA)
|
||||
|
||||
**Don't see your state?** You can still use the generic template or contribute your state's information (see Contributing section below).
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ Critical: 30-Day Data Deletion
|
||||
|
||||
**Flock Safety automatically deletes all camera data after 30 days** on a rolling basis.
|
||||
|
||||
**This means:**
|
||||
- You have ~30 days from when footage was captured to request it
|
||||
- Delays in agency response can result in permanent data loss
|
||||
- Always request expedited processing
|
||||
- Follow up immediately if delayed
|
||||
|
||||
**Our templates include expedited processing requests to address this issue.**
|
||||
|
||||
---
|
||||
|
||||
## 📋 What These Requests Will Get You
|
||||
|
||||
### ✅ Likely to Receive
|
||||
|
||||
- **Contracts and pricing** - Public agencies must disclose
|
||||
- **Policies and procedures** - Generally public records
|
||||
- **Meeting minutes** - Required to be public in most states
|
||||
- **Financial records** - How public money is spent
|
||||
- **Training materials** - Usually not exempt
|
||||
|
||||
### ⚠️ May Require Legal Challenge
|
||||
|
||||
- **Actual camera footage** - Privacy exemptions sometimes claimed
|
||||
- **Your own vehicle data** - Strongest legal argument for access
|
||||
- **Other people's vehicle data** - Usually denied on privacy grounds
|
||||
|
||||
### 🏆 Recent Legal Wins
|
||||
|
||||
Courts are increasingly ruling that Flock data is subject to public records laws:
|
||||
- **Virginia 2025**: Cardinal News won case for Flock footage
|
||||
- **Washington 2025**: Judge ordered police to release surveillance data
|
||||
- **General principle**: Public records law trumps vendor contracts
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips for Success
|
||||
|
||||
### 1. **Act Quickly**
|
||||
Flock deletes data after 30 days. File your request ASAP and request expedited processing.
|
||||
|
||||
### 2. **Request Your Own Vehicle Data**
|
||||
If you want specific footage, request data about YOUR OWN vehicle. This has the strongest legal backing.
|
||||
|
||||
Example: *"All images and data for license plate ABC-1234 (my vehicle, 2020 Honda Civic) from January 1-15, 2025."*
|
||||
|
||||
### 3. **Use State-Specific Language**
|
||||
Never use "FOIA" for state/local requests. Use your state's specific law name.
|
||||
|
||||
### 4. **Request Electronic Format**
|
||||
Usually faster and often free or cheaper than paper copies.
|
||||
|
||||
### 5. **Follow Up in Writing**
|
||||
Document all communications. If they miss the deadline, send a written follow-up citing the specific statute.
|
||||
|
||||
### 6. **Know Your Appeal Rights**
|
||||
Most states have administrative appeals processes. Be prepared to appeal denials.
|
||||
|
||||
### 7. **Fee Waivers May Apply**
|
||||
Many states waive fees for public interest requests, media requests, or non-commercial use.
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Legal Disclaimer
|
||||
|
||||
This tool generates templates for public records requests that are explicitly authorized by state and federal law. Public records requests are a constitutionally protected right under the First Amendment and state sunshine laws.
|
||||
|
||||
### This Tool Does NOT:
|
||||
- Perform hacking or unauthorized access
|
||||
- Bypass security measures
|
||||
- Violate any laws or regulations
|
||||
- Collect or transmit user data
|
||||
|
||||
### This Tool DOES:
|
||||
- Help citizens exercise their legal right to access public records
|
||||
- Provide accurate legal citations for state public records laws
|
||||
- Generate properly formatted request letters
|
||||
- Support government transparency and accountability
|
||||
|
||||
### Intended Use
|
||||
|
||||
Educational purposes and to assist citizens in exercising their legal rights to request public records under applicable state laws.
|
||||
|
||||
### Not Legal Advice
|
||||
|
||||
This tool provides templates and information, not legal advice. For specific legal questions about your request, consult an attorney familiar with your state's public records law.
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Want to help expand this tool?
|
||||
|
||||
### Add Your State
|
||||
|
||||
If your state isn't supported, you can add it:
|
||||
|
||||
1. Look up your state's public records law statute
|
||||
2. Find the mandated response timeframe
|
||||
3. Add entry to the `STATE_LAWS` object in `generate-flock-request.ts`
|
||||
|
||||
Example:
|
||||
```typescript
|
||||
XX: {
|
||||
name: "Your State",
|
||||
lawName: "Your State Public Records Act",
|
||||
statute: "State Code §XXX.XXX et seq.",
|
||||
responseTime: "within X days as required by State Code §XXX.XXX",
|
||||
specificTimeframe: X, // or null if no specific deadline
|
||||
notes: "Additional notes about your state's law"
|
||||
}
|
||||
```
|
||||
|
||||
### Report Issues
|
||||
|
||||
Found an error in legal citations? Please open an issue with:
|
||||
- Which state
|
||||
- What's incorrect
|
||||
- Correct citation/information
|
||||
- Source for verification
|
||||
|
||||
### Share Success Stories
|
||||
|
||||
Filed a request using these tools? Let us know how it went! Success stories help others understand what to expect.
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
### Research & FOIA Tracking
|
||||
- **MuckRock** - FOIA tracking and examples: https://www.muckrock.com
|
||||
- **DocumentCloud** - Document analysis and sharing
|
||||
- **National Freedom of Information Coalition**: https://www.nfoic.org/
|
||||
|
||||
### Legal Background
|
||||
- Each state has its own public records law (not "FOIA")
|
||||
- Federal FOIA (5 U.S.C. § 552) only applies to federal agencies
|
||||
- State laws generally favor disclosure with specific exemptions
|
||||
- Public records law typically trumps vendor contracts
|
||||
|
||||
### Digital Rights Organizations
|
||||
- **Electronic Frontier Foundation (EFF)**: https://www.eff.org
|
||||
- **ACLU**: https://www.aclu.org
|
||||
- **Fight for the Future**: https://www.fightforthefuture.org
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Security & Privacy
|
||||
|
||||
### Our Security Practices
|
||||
|
||||
- **Input validation** on all user inputs
|
||||
- **Path traversal prevention** for file operations
|
||||
- **No data collection** - everything runs locally
|
||||
- **No network calls** - completely offline
|
||||
- **Open source** - audit the code yourself
|
||||
|
||||
### For Your Safety
|
||||
|
||||
- Run scripts in a safe directory
|
||||
- Review generated letters before sending
|
||||
- Don't include sensitive information beyond what's required
|
||||
- Keep copies of all correspondence
|
||||
|
||||
---
|
||||
|
||||
## 📜 License
|
||||
|
||||
MIT License - See LICENSE file for details
|
||||
|
||||
This is free and open-source software. You are free to use, modify, and distribute it.
|
||||
|
||||
---
|
||||
|
||||
## 💬 Questions or Feedback?
|
||||
|
||||
- **Issues**: Open an issue on GitHub
|
||||
- **Discussions**: Use GitHub Discussions for questions
|
||||
- **Community**: Check the Clippies Zulip or your local privacy advocacy groups
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Acknowledgments
|
||||
|
||||
- **Louis Rossmann and Repair.org** - Started the Flock opposition movement with Denver investigation
|
||||
- Original template from Clippies Zulip community
|
||||
- Legal research from state government websites and NFOIC
|
||||
- Inspired by MuckRock, ACLU, and other transparency advocates
|
||||
- Built with Bun and TypeScript
|
||||
|
||||
### Relationship to Louis Rossmann's Denver Investigation
|
||||
|
||||
This project **complements** Louis Rossmann's Denver-specific investigation into the controversial $498,500 Flock contract. His guide focuses on deep investigative journalism for Denver, while our tools provide broad multi-state public records access for any jurisdiction.
|
||||
|
||||
- **Rossmann's guide** = Deep Denver investigation → [View Guide](https://consumerrights.wiki/w/Special_event_page:Forced_installation_of_Flock_cameras_in_Denver,_Colorado)
|
||||
- **Our tools** = Multi-state transparency toolkit
|
||||
- **Together** = Nationwide movement for surveillance accountability
|
||||
|
||||
---
|
||||
|
||||
**Remember: Transparency is a right, not a privilege. Government surveillance systems should be accountable to the communities they serve.**
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: November 2025
|
||||
**Maintained by**: Denver Flock Opposition community
|
||||
129
flock_request_template.md
Normal file
129
flock_request_template.md
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
# Streamlined Flock Safety Public Records Request Template
|
||||
|
||||
## Quick Copy-Paste Version
|
||||
|
||||
```
|
||||
[Date]
|
||||
|
||||
[Agency Name]
|
||||
[Agency Address]
|
||||
[City, State ZIP]
|
||||
|
||||
RE: Public Records Request - Flock Safety System
|
||||
|
||||
Dear Public Records Custodian:
|
||||
|
||||
This is a non-commercial public records request made pursuant to [Your State's Public Records Law - e.g., A.R.S. §39-121 for Arizona, C.R.S. §24-72-201 for Colorado].
|
||||
|
||||
I am requesting all records related to [Agency Name]'s relationship with Flock Group, Inc. (aka Flock Safety), including:
|
||||
|
||||
1. **Contracts & Agreements**: All contracts, amendments, intergovernmental agreements, and related documents between [Agency Name] and Flock Safety or any third parties regarding Flock products/services
|
||||
|
||||
2. **Financial Records**: Purchase orders, invoices, billing records, budgets, RFPs, bid responses, cost-benefit analyses, and funding sources (including grants)
|
||||
|
||||
3. **Policies & Procedures**: All policies, guidelines, procedures, or protocols (draft or final) regarding installation, operation, monitoring, data retention, data access, data sharing, or deletion
|
||||
|
||||
4. **Data Access Records**: Logs of all access requests (internal and external), data-sharing agreements, audit logs, and requests fulfilled or denied
|
||||
|
||||
5. **Meeting Records**: Minutes, agendas, notes, and presentations from meetings where Flock cameras or services were discussed
|
||||
|
||||
6. **Legal & Compliance**: Legal opinions, risk assessments, privacy impact assessments, compliance reviews, and related correspondence
|
||||
|
||||
7. **Technical Documentation**: System specifications, cybersecurity measures, data storage locations, interoperability documentation, and breach notifications
|
||||
|
||||
8. **Data Retention**: Policies on retention timeframes, deletion procedures, and actual deletion logs
|
||||
|
||||
9. **Training Materials**: Manuals, training materials, installation records, photographs, videos, and communications (emails, notes, etc.)
|
||||
|
||||
⚠️ **TIME-SENSITIVE**: Due to Flock Safety's 30-day data retention policy, I request expedited processing to preserve any relevant data that may be automatically deleted.
|
||||
|
||||
Please provide records in electronic format if available. If any portions are denied, please provide a written explanation citing the specific legal exemption.
|
||||
|
||||
I request that you respond within [timeframe based on state law - e.g., "promptly as required by A.R.S. §39-121" or "10 business days as required by C.R.S. §24-72-203(3)(b)"].
|
||||
|
||||
Thank you for your attention to this matter.
|
||||
|
||||
Sincerely,
|
||||
|
||||
[Your Name]
|
||||
[Your Address]
|
||||
[Your Email]
|
||||
[Your Phone]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## State-Specific Response Time References
|
||||
|
||||
**No specific deadline (respond "promptly"):**
|
||||
- Arizona (A.R.S. §39-121)
|
||||
- Others as applicable
|
||||
|
||||
**3 days or less:**
|
||||
- Arkansas: 3 days
|
||||
- Vermont: 2 days
|
||||
- Several others: 3 days
|
||||
|
||||
**5 days:**
|
||||
- California: 10 days
|
||||
- Illinois: 5 days
|
||||
- Pennsylvania: 5 days
|
||||
- Virginia: 5 days
|
||||
- West Virginia: 5 days
|
||||
|
||||
**10 days:**
|
||||
- Colorado: 10 business days (C.R.S. §24-72-203)
|
||||
- Iowa: 10-20 days
|
||||
- South Carolina: 10 days (20 if >24 months old)
|
||||
|
||||
**15 days:**
|
||||
- Delaware: 15 days
|
||||
- DC: 15 days
|
||||
- Michigan: 15 days
|
||||
|
||||
**20 days:**
|
||||
- Federal FOIA: 20 days
|
||||
- Maryland: 30 days
|
||||
|
||||
---
|
||||
|
||||
## Important Notes
|
||||
|
||||
### Critical Timing Issue
|
||||
⏱️ **Flock Safety deletes all data after 30 days** on a rolling basis. If your request is delayed or denied initially, specific footage may be permanently deleted. Request expedited processing and follow up immediately.
|
||||
|
||||
### What This Request Will Get You
|
||||
|
||||
✅ **Likely to receive:**
|
||||
- Contracts and pricing
|
||||
- Policies and procedures
|
||||
- Meeting minutes and financial records
|
||||
- Training materials and documentation
|
||||
|
||||
⚠️ **May require legal challenge:**
|
||||
- Actual camera footage/images (courts have ruled both ways)
|
||||
- Your own vehicle data (strongest legal argument)
|
||||
- Data about other vehicles (usually denied on privacy grounds)
|
||||
|
||||
### Tips for Success
|
||||
|
||||
1. **Be specific about your state's law** - Don't use "FOIA" for state requests
|
||||
2. **Request electronic format** - Faster and often free
|
||||
3. **Follow up in writing** - Document all communications
|
||||
4. **Know your state's fee structure** - Many states charge for copies
|
||||
5. **Request fee waiver if applicable** - Public interest exemptions may apply
|
||||
6. **Act quickly** - 30-day deletion window is real
|
||||
7. **Be prepared to appeal** - Many requests require administrative appeals
|
||||
|
||||
### Recent Legal Wins
|
||||
|
||||
Courts have increasingly ruled that Flock data is subject to public records laws:
|
||||
- **Virginia 2025**: Cardinal News won FOIA battle for Flock footage
|
||||
- **Washington 2025**: Judge ordered police to release surveillance camera data
|
||||
- **General principle**: FOIA/public records law trumps vendor contracts
|
||||
|
||||
### Requesting Your Own Vehicle Data
|
||||
|
||||
🎯 **Strongest legal argument**: Request footage of YOUR OWN vehicle for specific dates/times you traveled through areas with Flock cameras.
|
||||
|
||||
This approach has the highest success rate and clearest legal backing.
|
||||
512
generate-flock-request.ts
Executable file
512
generate-flock-request.ts
Executable file
|
|
@ -0,0 +1,512 @@
|
|||
#!/usr/bin/env bun
|
||||
|
||||
/**
|
||||
* Flock Safety Public Records Request Generator (Security Hardened)
|
||||
*
|
||||
* Interactive script to generate properly formatted public records requests
|
||||
* for Flock Safety camera systems with correct state-specific legal citations.
|
||||
*
|
||||
* Security Features:
|
||||
* - Input validation and sanitization
|
||||
* - Path traversal prevention
|
||||
* - Length limits on all inputs
|
||||
* - Email format validation
|
||||
* - Safe filename generation
|
||||
*/
|
||||
|
||||
import { writeFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import * as readline from 'readline';
|
||||
|
||||
// State-specific public records law information
|
||||
const STATE_LAWS = {
|
||||
AZ: {
|
||||
name: "Arizona",
|
||||
lawName: "Arizona Public Records Law",
|
||||
statute: "A.R.S. §39-121 et seq.",
|
||||
responseTime: "promptly as required by A.R.S. §39-121",
|
||||
specificTimeframe: null,
|
||||
notes: "Arizona does not have a specific mandated response time in days"
|
||||
},
|
||||
CO: {
|
||||
name: "Colorado",
|
||||
lawName: "Colorado Open Records Act (CORA)",
|
||||
statute: "C.R.S. §24-72-201 et seq.",
|
||||
responseTime: "within 10 business days as required by C.R.S. §24-72-203(3)(b)",
|
||||
specificTimeframe: 10,
|
||||
notes: "Colorado allows 10 business days for response"
|
||||
},
|
||||
CA: {
|
||||
name: "California",
|
||||
lawName: "California Public Records Act",
|
||||
statute: "Cal. Gov. Code §7920.000 et seq.",
|
||||
responseTime: "within 10 days as required by Cal. Gov. Code §7922.535",
|
||||
specificTimeframe: 10,
|
||||
notes: "California requires response within 10 days"
|
||||
},
|
||||
TX: {
|
||||
name: "Texas",
|
||||
lawName: "Texas Public Information Act",
|
||||
statute: "Tex. Gov't Code §552.001 et seq.",
|
||||
responseTime: "promptly as required by Tex. Gov't Code §552.221",
|
||||
specificTimeframe: 10,
|
||||
notes: "Texas requires response within 10 business days"
|
||||
},
|
||||
IL: {
|
||||
name: "Illinois",
|
||||
lawName: "Illinois Freedom of Information Act (FOIA)",
|
||||
statute: "5 ILCS 140/1 et seq.",
|
||||
responseTime: "within 5 business days as required by 5 ILCS 140/3(d)",
|
||||
specificTimeframe: 5,
|
||||
notes: "Illinois requires response within 5 business days"
|
||||
},
|
||||
VA: {
|
||||
name: "Virginia",
|
||||
lawName: "Virginia Freedom of Information Act (FOIA)",
|
||||
statute: "Va. Code §2.2-3700 et seq.",
|
||||
responseTime: "within 5 working days as required by Va. Code §2.2-3704(B)",
|
||||
specificTimeframe: 5,
|
||||
notes: "Virginia requires response within 5 working days"
|
||||
},
|
||||
NY: {
|
||||
name: "New York",
|
||||
lawName: "New York Freedom of Information Law (FOIL)",
|
||||
statute: "N.Y. Pub. Off. Law §87 et seq.",
|
||||
responseTime: "within 5 business days as required by N.Y. Pub. Off. Law §89(3)",
|
||||
specificTimeframe: 5,
|
||||
notes: "New York requires acknowledgment within 5 business days"
|
||||
},
|
||||
FL: {
|
||||
name: "Florida",
|
||||
lawName: "Florida Public Records Law",
|
||||
statute: "Fla. Stat. §119.01 et seq.",
|
||||
responseTime: "within a reasonable time as required by Fla. Stat. §119.07(1)(a)",
|
||||
specificTimeframe: null,
|
||||
notes: "Florida requires 'reasonable time' - no specific deadline"
|
||||
},
|
||||
WA: {
|
||||
name: "Washington",
|
||||
lawName: "Washington Public Records Act",
|
||||
statute: "RCW 42.56 et seq.",
|
||||
responseTime: "within 5 business days as required by RCW 42.56.520",
|
||||
specificTimeframe: 5,
|
||||
notes: "Washington requires response within 5 business days"
|
||||
},
|
||||
OR: {
|
||||
name: "Oregon",
|
||||
lawName: "Oregon Public Records Law",
|
||||
statute: "ORS 192.311 et seq.",
|
||||
responseTime: "within a reasonable time as required by ORS 192.329",
|
||||
specificTimeframe: null,
|
||||
notes: "Oregon requires 'reasonable time' - no specific deadline"
|
||||
},
|
||||
GA: {
|
||||
name: "Georgia",
|
||||
lawName: "Georgia Open Records Act",
|
||||
statute: "O.C.G.A. §50-18-70 et seq.",
|
||||
responseTime: "within 3 business days as required by O.C.G.A. §50-18-71(b)(1)",
|
||||
specificTimeframe: 3,
|
||||
notes: "Georgia requires response within 3 business days"
|
||||
},
|
||||
NC: {
|
||||
name: "North Carolina",
|
||||
lawName: "North Carolina Public Records Law",
|
||||
statute: "N.C. Gen. Stat. §132-1 et seq.",
|
||||
responseTime: "within a reasonable time as required by N.C. Gen. Stat. §132-6",
|
||||
specificTimeframe: null,
|
||||
notes: "North Carolina requires 'reasonable time' - no specific deadline"
|
||||
},
|
||||
TN: {
|
||||
name: "Tennessee",
|
||||
lawName: "Tennessee Public Records Act",
|
||||
statute: "Tenn. Code Ann. §10-7-503 et seq.",
|
||||
responseTime: "within 7 business days as required by Tenn. Code Ann. §10-7-503(a)(2)(B)",
|
||||
specificTimeframe: 7,
|
||||
notes: "Tennessee requires response within 7 business days"
|
||||
},
|
||||
MA: {
|
||||
name: "Massachusetts",
|
||||
lawName: "Massachusetts Public Records Law",
|
||||
statute: "Mass. Gen. Laws ch. 66, §10 et seq.",
|
||||
responseTime: "within 10 business days as required by Mass. Gen. Laws ch. 66, §10(b)",
|
||||
specificTimeframe: 10,
|
||||
notes: "Massachusetts requires response within 10 business days"
|
||||
},
|
||||
PA: {
|
||||
name: "Pennsylvania",
|
||||
lawName: "Pennsylvania Right-to-Know Law",
|
||||
statute: "65 Pa.C.S. §67.101 et seq.",
|
||||
responseTime: "within 5 business days as required by 65 Pa.C.S. §67.901",
|
||||
specificTimeframe: 5,
|
||||
notes: "Pennsylvania requires response within 5 business days"
|
||||
},
|
||||
OH: {
|
||||
name: "Ohio",
|
||||
lawName: "Ohio Public Records Act",
|
||||
statute: "Ohio Rev. Code §149.43 et seq.",
|
||||
responseTime: "within a reasonable time as required by Ohio Rev. Code §149.43(B)",
|
||||
specificTimeframe: null,
|
||||
notes: "Ohio requires 'reasonable time' - no specific deadline"
|
||||
},
|
||||
MI: {
|
||||
name: "Michigan",
|
||||
lawName: "Michigan Freedom of Information Act (FOIA)",
|
||||
statute: "MCL 15.231 et seq.",
|
||||
responseTime: "within 15 business days as required by MCL 15.235(2)",
|
||||
specificTimeframe: 15,
|
||||
notes: "Michigan requires response within 15 business days"
|
||||
},
|
||||
MD: {
|
||||
name: "Maryland",
|
||||
lawName: "Maryland Public Information Act",
|
||||
statute: "Md. Code Ann., Gen. Prov. §4-101 et seq.",
|
||||
responseTime: "within 30 days as required by Md. Code Ann., Gen. Prov. §4-203(c)",
|
||||
specificTimeframe: 30,
|
||||
notes: "Maryland requires response within 30 days"
|
||||
},
|
||||
NV: {
|
||||
name: "Nevada",
|
||||
lawName: "Nevada Public Records Law",
|
||||
statute: "Nev. Rev. Stat. §239.010 et seq.",
|
||||
responseTime: "within 5 business days as required by Nev. Rev. Stat. §239.0107",
|
||||
specificTimeframe: 5,
|
||||
notes: "Nevada requires response within 5 business days"
|
||||
},
|
||||
NM: {
|
||||
name: "New Mexico",
|
||||
lawName: "New Mexico Inspection of Public Records Act",
|
||||
statute: "NMSA 1978, §14-2-1 et seq.",
|
||||
responseTime: "within 3 business days as required by NMSA 1978, §14-2-8(D)",
|
||||
specificTimeframe: 3,
|
||||
notes: "New Mexico requires response within 3 business days"
|
||||
},
|
||||
// Add more states as needed
|
||||
};
|
||||
|
||||
// Security: Input validation and sanitization functions
|
||||
|
||||
/**
|
||||
* Sanitize text input - removes control characters, limits length
|
||||
*/
|
||||
function sanitizeText(input: string, maxLength: number = 200): string {
|
||||
return input
|
||||
.trim()
|
||||
.replace(/[\x00-\x1F\x7F]/g, '') // Remove control characters
|
||||
.slice(0, maxLength); // Enforce length limit
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize filename - only allow safe characters
|
||||
*/
|
||||
function sanitizeFilename(input: string): string {
|
||||
return input
|
||||
.trim()
|
||||
.replace(/[^a-zA-Z0-9\s\-_]/g, '') // Only alphanumeric, spaces, hyphens, underscores
|
||||
.replace(/\s+/g, '_') // Replace spaces with underscores
|
||||
.replace(/_{2,}/g, '_') // Collapse multiple underscores
|
||||
.slice(0, 50); // Limit filename length
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate email format (basic check)
|
||||
*/
|
||||
function isValidEmail(email: string): boolean {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return emailRegex.test(email) && email.length <= 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate ZIP code (US format)
|
||||
*/
|
||||
function isValidZip(zip: string): boolean {
|
||||
const zipRegex = /^\d{5}(-\d{4})?$/;
|
||||
return zipRegex.test(zip.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate state code (2 letters)
|
||||
*/
|
||||
function normalizeStateCode(code: string): string {
|
||||
return code.trim().toUpperCase().replace(/[^A-Z]/g, '').slice(0, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate license plate (alphanumeric, hyphens, spaces)
|
||||
*/
|
||||
function sanitizeLicensePlate(plate: string): string {
|
||||
return plate
|
||||
.trim()
|
||||
.toUpperCase()
|
||||
.replace(/[^A-Z0-9\s\-]/g, '')
|
||||
.slice(0, 20);
|
||||
}
|
||||
|
||||
// Helper function to read input from user
|
||||
function prompt(question: string): Promise<string> {
|
||||
return new Promise((resolve) => {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
rl.question(question, (answer) => {
|
||||
rl.close();
|
||||
resolve(answer.trim());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to get current date in format: Month Day, Year
|
||||
function getCurrentDate(): string {
|
||||
const date = new Date();
|
||||
return date.toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
});
|
||||
}
|
||||
|
||||
// Main interactive function
|
||||
async function main() {
|
||||
console.log("╔══════════════════════════════════════════════════════════════╗");
|
||||
console.log("║ Flock Safety Public Records Request Generator ║");
|
||||
console.log("║ Generates state-specific public records requests ║");
|
||||
console.log("║ (Security Hardened Version) ║");
|
||||
console.log("╚══════════════════════════════════════════════════════════════╝\n");
|
||||
|
||||
// Get state
|
||||
console.log("\nAvailable states:");
|
||||
Object.keys(STATE_LAWS).sort().forEach(code => {
|
||||
console.log(` ${code} - ${STATE_LAWS[code as keyof typeof STATE_LAWS].name}`);
|
||||
});
|
||||
|
||||
const rawStateCode = await prompt("\nEnter your state code (e.g., AZ, CO, CA): ");
|
||||
const stateCode = normalizeStateCode(rawStateCode);
|
||||
|
||||
if (!STATE_LAWS[stateCode as keyof typeof STATE_LAWS]) {
|
||||
console.error(`\n❌ Error: State code "${stateCode}" not found in database.`);
|
||||
console.error("Please add your state's information to the STATE_LAWS object in the script,");
|
||||
console.error("or use the generic template in foia_request_streamlined.md\n");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const stateLaw = STATE_LAWS[stateCode as keyof typeof STATE_LAWS];
|
||||
|
||||
// Get agency information
|
||||
console.log("\n─────────────────────────────────────────────────────────────");
|
||||
console.log("Agency Information");
|
||||
console.log("─────────────────────────────────────────────────────────────");
|
||||
|
||||
const agencyName = sanitizeText(await prompt("Agency name (e.g., Denver Police Department): "), 200);
|
||||
if (!agencyName) {
|
||||
console.error("❌ Error: Agency name is required");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const agencyAddress = sanitizeText(await prompt("Agency street address: "), 200);
|
||||
const city = sanitizeText(await prompt("City: "), 100);
|
||||
const rawZip = await prompt("ZIP code: ");
|
||||
|
||||
if (!isValidZip(rawZip)) {
|
||||
console.error("❌ Error: Invalid ZIP code format (use 12345 or 12345-6789)");
|
||||
process.exit(1);
|
||||
}
|
||||
const zip = rawZip.trim();
|
||||
|
||||
// Get requester information
|
||||
console.log("\n─────────────────────────────────────────────────────────────");
|
||||
console.log("Your Information");
|
||||
console.log("─────────────────────────────────────────────────────────────");
|
||||
|
||||
const yourName = sanitizeText(await prompt("Your full name: "), 100);
|
||||
if (!yourName) {
|
||||
console.error("❌ Error: Your name is required");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const yourAddress = sanitizeText(await prompt("Your street address: "), 200);
|
||||
const yourCity = sanitizeText(await prompt("Your city: "), 100);
|
||||
const yourState = sanitizeText(await prompt("Your state: "), 50);
|
||||
|
||||
const rawYourZip = await prompt("Your ZIP: ");
|
||||
if (!isValidZip(rawYourZip)) {
|
||||
console.error("❌ Error: Invalid ZIP code format");
|
||||
process.exit(1);
|
||||
}
|
||||
const yourZip = rawYourZip.trim();
|
||||
|
||||
const rawEmail = await prompt("Your email: ");
|
||||
if (!isValidEmail(rawEmail)) {
|
||||
console.error("❌ Error: Invalid email format");
|
||||
process.exit(1);
|
||||
}
|
||||
const yourEmail = rawEmail.trim();
|
||||
|
||||
const yourPhone = sanitizeText(await prompt("Your phone (optional): "), 20);
|
||||
|
||||
// Ask about specific requests
|
||||
console.log("\n─────────────────────────────────────────────────────────────");
|
||||
console.log("Request Customization");
|
||||
console.log("─────────────────────────────────────────────────────────────");
|
||||
|
||||
const includeFootage = await prompt("Request your own vehicle footage? (y/n): ");
|
||||
let vehicleInfo = "";
|
||||
|
||||
if (includeFootage.toLowerCase() === 'y') {
|
||||
const rawPlate = await prompt("Your license plate number: ");
|
||||
const licensePlate = sanitizeLicensePlate(rawPlate);
|
||||
|
||||
if (!licensePlate) {
|
||||
console.error("❌ Error: Invalid license plate");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const vehicleDesc = sanitizeText(await prompt("Vehicle description (e.g., '2020 Honda Civic, blue'): "), 100);
|
||||
const dateRange = sanitizeText(await prompt("Date range (e.g., 'January 1-15, 2025'): "), 50);
|
||||
|
||||
vehicleInfo = `\n\n10. **Vehicle-Specific Request**: All images, footage, and associated data for license plate ${licensePlate} (${vehicleDesc}) for the period of ${dateRange}. This is a request for my own vehicle data.`;
|
||||
}
|
||||
|
||||
const expedited = await prompt("Request expedited processing due to 30-day deletion? (y/n): ");
|
||||
|
||||
// Generate the letter
|
||||
const letter = generateLetter({
|
||||
date: getCurrentDate(),
|
||||
agencyName,
|
||||
agencyAddress,
|
||||
city,
|
||||
state: stateLaw.name,
|
||||
stateCode,
|
||||
zip,
|
||||
lawName: stateLaw.lawName,
|
||||
statute: stateLaw.statute,
|
||||
responseTime: stateLaw.responseTime,
|
||||
yourName,
|
||||
yourAddress,
|
||||
yourCity,
|
||||
yourState,
|
||||
yourZip,
|
||||
yourEmail,
|
||||
yourPhone,
|
||||
vehicleInfo,
|
||||
expedited: expedited.toLowerCase() === 'y'
|
||||
});
|
||||
|
||||
// Security: Safe filename generation - restrict to current directory
|
||||
const safeAgencyName = sanitizeFilename(agencyName);
|
||||
const timestamp = Date.now();
|
||||
const filename = `foia_request_${safeAgencyName}_${timestamp}.txt`;
|
||||
|
||||
// Security: Use path.join to ensure file stays in current directory
|
||||
const filepath = join(process.cwd(), filename);
|
||||
|
||||
// Additional safety check: ensure filepath is still in current directory
|
||||
if (!filepath.startsWith(process.cwd())) {
|
||||
console.error("❌ Security Error: Invalid file path detected");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
writeFileSync(filepath, letter);
|
||||
|
||||
console.log("\n╔══════════════════════════════════════════════════════════════╗");
|
||||
console.log("║ ✅ Request Generated Successfully! ║");
|
||||
console.log("╚══════════════════════════════════════════════════════════════╝");
|
||||
console.log(`\nSaved to: ${filename}`);
|
||||
console.log("\n📋 Preview:\n");
|
||||
console.log("─────────────────────────────────────────────────────────────");
|
||||
console.log(letter);
|
||||
console.log("─────────────────────────────────────────────────────────────");
|
||||
|
||||
console.log("\n💡 Next Steps:");
|
||||
console.log(" 1. Review the generated request carefully");
|
||||
console.log(" 2. Verify the agency contact information");
|
||||
console.log(" 3. Send via email or mail to the agency");
|
||||
console.log(" 4. Keep a copy for your records");
|
||||
console.log(" 5. Follow up if no response within the legal timeframe");
|
||||
|
||||
if (expedited) {
|
||||
console.log("\n⚠️ IMPORTANT: You requested expedited processing due to");
|
||||
console.log(" Flock's 30-day deletion policy. Follow up quickly!");
|
||||
}
|
||||
|
||||
console.log("\n");
|
||||
}
|
||||
|
||||
function generateLetter(params: {
|
||||
date: string;
|
||||
agencyName: string;
|
||||
agencyAddress: string;
|
||||
city: string;
|
||||
state: string;
|
||||
stateCode: string;
|
||||
zip: string;
|
||||
lawName: string;
|
||||
statute: string;
|
||||
responseTime: string;
|
||||
yourName: string;
|
||||
yourAddress: string;
|
||||
yourCity: string;
|
||||
yourState: string;
|
||||
yourZip: string;
|
||||
yourEmail: string;
|
||||
yourPhone: string;
|
||||
vehicleInfo: string;
|
||||
expedited: boolean;
|
||||
}): string {
|
||||
const expeditedText = params.expedited ? `
|
||||
|
||||
⚠️ TIME-SENSITIVE REQUEST: Due to Flock Safety's 30-day rolling data deletion policy, I request expedited processing of this request to preserve any relevant data that may be automatically deleted during processing.` : '';
|
||||
|
||||
// Note: All params have already been sanitized before reaching this function
|
||||
return `${params.date}
|
||||
|
||||
${params.agencyName}
|
||||
${params.agencyAddress}
|
||||
${params.city}, ${params.state} ${params.zip}
|
||||
|
||||
RE: Public Records Request - Flock Safety System
|
||||
|
||||
Dear Public Records Custodian:
|
||||
|
||||
This is a non-commercial public records request made pursuant to the ${params.lawName} (${params.statute}).
|
||||
|
||||
I am requesting all records related to ${params.agencyName}'s relationship with Flock Group, Inc. (aka Flock Safety, including all subsidiaries), including:
|
||||
|
||||
1. **Contracts & Agreements**: All contracts, amendments, intergovernmental agreements, and related documents between ${params.agencyName} and Flock Safety or any third parties regarding Flock products/services
|
||||
|
||||
2. **Financial Records**: Purchase orders, invoices, billing records, budgets, RFPs, bid responses, cost-benefit analyses, and funding sources (including grants)
|
||||
|
||||
3. **Policies & Procedures**: All policies, guidelines, procedures, or protocols (draft or final) regarding installation, operation, monitoring, data retention, data access, data sharing, or deletion
|
||||
|
||||
4. **Data Access Records**: Logs of all access requests (internal and external), data-sharing agreements, audit logs, and requests fulfilled or denied
|
||||
|
||||
5. **Meeting Records**: Minutes, agendas, notes, and presentations from meetings where Flock cameras or services were discussed
|
||||
|
||||
6. **Legal & Compliance**: Legal opinions, risk assessments, privacy impact assessments, compliance reviews, and related correspondence
|
||||
|
||||
7. **Technical Documentation**: System specifications, cybersecurity measures, data storage locations, interoperability documentation, and breach notifications
|
||||
|
||||
8. **Data Retention**: Policies on retention timeframes, deletion procedures, and actual deletion logs
|
||||
|
||||
9. **Training Materials**: Manuals, training materials, installation records, photographs, videos, and communications (emails, notes, etc.)${params.vehicleInfo}${expeditedText}
|
||||
|
||||
Please provide records in electronic format if available. If any portions of this request are denied, please provide a written explanation citing the specific legal exemption claimed.
|
||||
|
||||
I request that you respond ${params.responseTime}.
|
||||
|
||||
Please send the requested records to:
|
||||
|
||||
${params.yourName}
|
||||
${params.yourAddress}
|
||||
${params.yourCity}, ${params.yourState} ${params.yourZip}
|
||||
Email: ${params.yourEmail}${params.yourPhone ? `\nPhone: ${params.yourPhone}` : ''}
|
||||
|
||||
Thank you for your attention to this matter.
|
||||
|
||||
Sincerely,
|
||||
|
||||
${params.yourName}`;
|
||||
}
|
||||
|
||||
// Run the script
|
||||
main().catch(console.error);
|
||||
264
lookup-state-law.ts
Executable file
264
lookup-state-law.ts
Executable file
|
|
@ -0,0 +1,264 @@
|
|||
#!/usr/bin/env bun
|
||||
|
||||
/**
|
||||
* Quick State Public Records Law Lookup
|
||||
*
|
||||
* Fast command-line tool to get the correct legal citation for your state.
|
||||
* Usage: bun lookup-state-law.ts <STATE_CODE>
|
||||
* Example: bun lookup-state-law.ts CO
|
||||
*/
|
||||
|
||||
// State-specific public records law information
|
||||
const STATE_LAWS = {
|
||||
AZ: {
|
||||
name: "Arizona",
|
||||
lawName: "Arizona Public Records Law",
|
||||
statute: "A.R.S. §39-121 et seq.",
|
||||
responseTime: "promptly as required by A.R.S. §39-121",
|
||||
specificTimeframe: null,
|
||||
notes: "Arizona does not have a specific mandated response time in days"
|
||||
},
|
||||
CO: {
|
||||
name: "Colorado",
|
||||
lawName: "Colorado Open Records Act (CORA)",
|
||||
statute: "C.R.S. §24-72-201 et seq.",
|
||||
responseTime: "within 10 business days as required by C.R.S. §24-72-203(3)(b)",
|
||||
specificTimeframe: 10,
|
||||
notes: "Colorado allows 10 business days for response"
|
||||
},
|
||||
CA: {
|
||||
name: "California",
|
||||
lawName: "California Public Records Act",
|
||||
statute: "Cal. Gov. Code §7920.000 et seq.",
|
||||
responseTime: "within 10 days as required by Cal. Gov. Code §7922.535",
|
||||
specificTimeframe: 10,
|
||||
notes: "California requires response within 10 days"
|
||||
},
|
||||
TX: {
|
||||
name: "Texas",
|
||||
lawName: "Texas Public Information Act",
|
||||
statute: "Tex. Gov't Code §552.001 et seq.",
|
||||
responseTime: "promptly as required by Tex. Gov't Code §552.221",
|
||||
specificTimeframe: 10,
|
||||
notes: "Texas requires response within 10 business days"
|
||||
},
|
||||
IL: {
|
||||
name: "Illinois",
|
||||
lawName: "Illinois Freedom of Information Act (FOIA)",
|
||||
statute: "5 ILCS 140/1 et seq.",
|
||||
responseTime: "within 5 business days as required by 5 ILCS 140/3(d)",
|
||||
specificTimeframe: 5,
|
||||
notes: "Illinois requires response within 5 business days"
|
||||
},
|
||||
VA: {
|
||||
name: "Virginia",
|
||||
lawName: "Virginia Freedom of Information Act (FOIA)",
|
||||
statute: "Va. Code §2.2-3700 et seq.",
|
||||
responseTime: "within 5 working days as required by Va. Code §2.2-3704(B)",
|
||||
specificTimeframe: 5,
|
||||
notes: "Virginia requires response within 5 working days"
|
||||
},
|
||||
NY: {
|
||||
name: "New York",
|
||||
lawName: "New York Freedom of Information Law (FOIL)",
|
||||
statute: "N.Y. Pub. Off. Law §87 et seq.",
|
||||
responseTime: "within 5 business days as required by N.Y. Pub. Off. Law §89(3)",
|
||||
specificTimeframe: 5,
|
||||
notes: "New York requires acknowledgment within 5 business days"
|
||||
},
|
||||
FL: {
|
||||
name: "Florida",
|
||||
lawName: "Florida Public Records Law",
|
||||
statute: "Fla. Stat. §119.01 et seq.",
|
||||
responseTime: "within a reasonable time as required by Fla. Stat. §119.07(1)(a)",
|
||||
specificTimeframe: null,
|
||||
notes: "Florida requires 'reasonable time' - no specific deadline"
|
||||
},
|
||||
WA: {
|
||||
name: "Washington",
|
||||
lawName: "Washington Public Records Act",
|
||||
statute: "RCW 42.56 et seq.",
|
||||
responseTime: "within 5 business days as required by RCW 42.56.520",
|
||||
specificTimeframe: 5,
|
||||
notes: "Washington requires response within 5 business days"
|
||||
},
|
||||
OR: {
|
||||
name: "Oregon",
|
||||
lawName: "Oregon Public Records Law",
|
||||
statute: "ORS 192.311 et seq.",
|
||||
responseTime: "within a reasonable time as required by ORS 192.329",
|
||||
specificTimeframe: null,
|
||||
notes: "Oregon requires 'reasonable time' - no specific deadline"
|
||||
},
|
||||
GA: {
|
||||
name: "Georgia",
|
||||
lawName: "Georgia Open Records Act",
|
||||
statute: "O.C.G.A. §50-18-70 et seq.",
|
||||
responseTime: "within 3 business days as required by O.C.G.A. §50-18-71(b)(1)",
|
||||
specificTimeframe: 3,
|
||||
notes: "Georgia requires response within 3 business days"
|
||||
},
|
||||
NC: {
|
||||
name: "North Carolina",
|
||||
lawName: "North Carolina Public Records Law",
|
||||
statute: "N.C. Gen. Stat. §132-1 et seq.",
|
||||
responseTime: "within a reasonable time as required by N.C. Gen. Stat. §132-6",
|
||||
specificTimeframe: null,
|
||||
notes: "North Carolina requires 'reasonable time' - no specific deadline"
|
||||
},
|
||||
TN: {
|
||||
name: "Tennessee",
|
||||
lawName: "Tennessee Public Records Act",
|
||||
statute: "Tenn. Code Ann. §10-7-503 et seq.",
|
||||
responseTime: "within 7 business days as required by Tenn. Code Ann. §10-7-503(a)(2)(B)",
|
||||
specificTimeframe: 7,
|
||||
notes: "Tennessee requires response within 7 business days"
|
||||
},
|
||||
MA: {
|
||||
name: "Massachusetts",
|
||||
lawName: "Massachusetts Public Records Law",
|
||||
statute: "Mass. Gen. Laws ch. 66, §10 et seq.",
|
||||
responseTime: "within 10 business days as required by Mass. Gen. Laws ch. 66, §10(b)",
|
||||
specificTimeframe: 10,
|
||||
notes: "Massachusetts requires response within 10 business days"
|
||||
},
|
||||
PA: {
|
||||
name: "Pennsylvania",
|
||||
lawName: "Pennsylvania Right-to-Know Law",
|
||||
statute: "65 Pa.C.S. §67.101 et seq.",
|
||||
responseTime: "within 5 business days as required by 65 Pa.C.S. §67.901",
|
||||
specificTimeframe: 5,
|
||||
notes: "Pennsylvania requires response within 5 business days"
|
||||
},
|
||||
OH: {
|
||||
name: "Ohio",
|
||||
lawName: "Ohio Public Records Act",
|
||||
statute: "Ohio Rev. Code §149.43 et seq.",
|
||||
responseTime: "within a reasonable time as required by Ohio Rev. Code §149.43(B)",
|
||||
specificTimeframe: null,
|
||||
notes: "Ohio requires 'reasonable time' - no specific deadline"
|
||||
},
|
||||
MI: {
|
||||
name: "Michigan",
|
||||
lawName: "Michigan Freedom of Information Act (FOIA)",
|
||||
statute: "MCL 15.231 et seq.",
|
||||
responseTime: "within 15 business days as required by MCL 15.235(2)",
|
||||
specificTimeframe: 15,
|
||||
notes: "Michigan requires response within 15 business days"
|
||||
},
|
||||
MD: {
|
||||
name: "Maryland",
|
||||
lawName: "Maryland Public Information Act",
|
||||
statute: "Md. Code Ann., Gen. Prov. §4-101 et seq.",
|
||||
responseTime: "within 30 days as required by Md. Code Ann., Gen. Prov. §4-203(c)",
|
||||
specificTimeframe: 30,
|
||||
notes: "Maryland requires response within 30 days"
|
||||
},
|
||||
NV: {
|
||||
name: "Nevada",
|
||||
lawName: "Nevada Public Records Law",
|
||||
statute: "Nev. Rev. Stat. §239.010 et seq.",
|
||||
responseTime: "within 5 business days as required by Nev. Rev. Stat. §239.0107",
|
||||
specificTimeframe: 5,
|
||||
notes: "Nevada requires response within 5 business days"
|
||||
},
|
||||
NM: {
|
||||
name: "New Mexico",
|
||||
lawName: "New Mexico Inspection of Public Records Act",
|
||||
statute: "NMSA 1978, §14-2-1 et seq.",
|
||||
responseTime: "within 3 business days as required by NMSA 1978, §14-2-8(D)",
|
||||
specificTimeframe: 3,
|
||||
notes: "New Mexico requires response within 3 business days"
|
||||
},
|
||||
};
|
||||
|
||||
// Parse command line arguments
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.length === 0) {
|
||||
console.log("╔══════════════════════════════════════════════════════════════╗");
|
||||
console.log("║ State Public Records Law Quick Reference ║");
|
||||
console.log("╚══════════════════════════════════════════════════════════════╝\n");
|
||||
console.log("Usage: bun lookup-state-law.ts <STATE_CODE>\n");
|
||||
console.log("Example: bun lookup-state-law.ts CO\n");
|
||||
console.log("Available states:");
|
||||
Object.keys(STATE_LAWS).sort().forEach(code => {
|
||||
const law = STATE_LAWS[code as keyof typeof STATE_LAWS];
|
||||
console.log(` ${code.padEnd(4)} - ${law.name}`);
|
||||
});
|
||||
console.log("\nTo list all states with full details:");
|
||||
console.log(" bun lookup-state-law.ts --all\n");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Handle --all flag
|
||||
if (args[0] === '--all' || args[0] === '-a') {
|
||||
console.log("╔══════════════════════════════════════════════════════════════╗");
|
||||
console.log("║ All State Public Records Laws ║");
|
||||
console.log("╚══════════════════════════════════════════════════════════════╝\n");
|
||||
|
||||
Object.keys(STATE_LAWS).sort().forEach(code => {
|
||||
const law = STATE_LAWS[code as keyof typeof STATE_LAWS];
|
||||
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
|
||||
console.log(`${code} - ${law.name}`);
|
||||
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
|
||||
console.log(`Law Name: ${law.lawName}`);
|
||||
console.log(`Statute: ${law.statute}`);
|
||||
console.log(`Response Time: ${law.responseTime}`);
|
||||
if (law.specificTimeframe) {
|
||||
console.log(`Deadline: ${law.specificTimeframe} days`);
|
||||
}
|
||||
console.log(`Notes: ${law.notes}`);
|
||||
console.log();
|
||||
});
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Handle state lookup
|
||||
const stateCode = args[0].trim().toUpperCase();
|
||||
|
||||
if (!STATE_LAWS[stateCode as keyof typeof STATE_LAWS]) {
|
||||
console.error(`\n❌ Error: State code "${stateCode}" not found.\n`);
|
||||
console.error("Available states:");
|
||||
Object.keys(STATE_LAWS).sort().forEach(code => {
|
||||
console.error(` ${code} - ${STATE_LAWS[code as keyof typeof STATE_LAWS].name}`);
|
||||
});
|
||||
console.error("\n");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const law = STATE_LAWS[stateCode as keyof typeof STATE_LAWS];
|
||||
|
||||
console.log("\n╔══════════════════════════════════════════════════════════════╗");
|
||||
console.log(`║ ${law.name.padEnd(58)} ║`);
|
||||
console.log("╚══════════════════════════════════════════════════════════════╝\n");
|
||||
|
||||
console.log("📖 Official Law Name:");
|
||||
console.log(` ${law.lawName}\n`);
|
||||
|
||||
console.log("📋 Statute Citation:");
|
||||
console.log(` ${law.statute}\n`);
|
||||
|
||||
console.log("⏱️ Response Timeframe:");
|
||||
console.log(` ${law.responseTime}\n`);
|
||||
|
||||
if (law.specificTimeframe) {
|
||||
console.log("📅 Deadline:");
|
||||
console.log(` ${law.specificTimeframe} ${law.specificTimeframe === 1 ? 'day' : 'days'}\n`);
|
||||
}
|
||||
|
||||
console.log("📝 Notes:");
|
||||
console.log(` ${law.notes}\n`);
|
||||
|
||||
console.log("💡 How to Use in Your Request:");
|
||||
console.log(` "This is a non-commercial public records request made pursuant`);
|
||||
console.log(` to the ${law.lawName} (${law.statute})."`);
|
||||
console.log();
|
||||
console.log(` "I request that you respond ${law.responseTime}."`);
|
||||
console.log();
|
||||
|
||||
console.log("🔗 Related Tools:");
|
||||
console.log(" • Full request generator: bun generate-flock-request-secure.ts");
|
||||
console.log(" • Template file: flock_request_template.md");
|
||||
console.log(" • All states: bun lookup-state-law.ts --all\n");
|
||||
Loading…
Add table
Reference in a new issue