// from the Starship/CoreID project - app/ldap/controllers/Users.controller.jsconst LDAPController = require('./LDAPController')const LDAP = require('ldapjs')const bcrypt = require('bcrypt')class UsersController extends LDAPController {  static get services() {    return [      ...super.services,      'output',      'ldap_server',      'models',      'configs',      'auth'    ]  }  constructor() {    super()    this.User = this.models.get('auth:User')  }  // Might need to override compare to support special handling for userPassword  // TODO generalize some of the addition logic  // TODO rework some of the registration and validation logic  async add_people(req, res, next) {    const Setting = this.models.get('Setting')    if ( !(await Setting.get('auth.allow_registration')) ) {      return next(new LDAP.InsufficientAccessRightsError('Operation not enabled.'))    }    if ( !req.user.can('ldap:add:users') ) {      return next(new LDAP.InsufficientAccessRightsError())    }    // make sure the add DN is in the auth_dn    const auth_dn = this.ldap_server.auth_dn()    if ( !auth_dn.parentOf(req.dn) ) {      this.output.warn(`Attempted to perform user insertion on invalid DN: ${req.dn.format(this.configs.get('ldap:server.format'))}`)      return next(new LDAP.InsufficientAccessRightsError())    }    // make sure the user object doesn't already exist    const existing_user = await this.get_resource_from_dn(req.dn)    if ( existing_user ) {      return next(new LDAP.EntryAlreadyExistsError())    }    // build the user object from the request attributes    const req_data = req.toObject().attributes    const register_data = {      first_name: req_data.cn ? req_data.cn[0] : '',      last_name: req_data.sn ? req_data.sn[0] : '',      email: req_data.mail ? req_data.mail[0] : '',      username: req_data.uid ? req_data.uid[0].toLowerCase() : '',      password: req_data.userpassword ? req_data.userpassword[0] : '',    }    // TODO add data fields// from the Starship/CoreID project - app/ldap/controllers/Users.controller.jsconst LDAPController = require('./LDAPController')const LDAP = require('ldapjs')const bcrypt = require('bcrypt')class UsersController extends LDAPController {  static get services() {    return [      ...super.services,      'output',      'ldap_server',      'models',      'configs',      'auth'    ]  }  constructor() {    super()    this.User = this.models.get('auth:User')  }  // Might need to override compare to support special handling for userPassword  // TODO generalize some of the addition logic  // TODO rework some of the registration and validation logic  async add_people(req, res, next) {    const Setting = this.models.get('Setting')    if ( !(await Setting.get('auth.allow_registration')) ) {      return next(new LDAP.InsufficientAccessRightsError('Operation not enabled.'))    }    if ( !req.user.can('ldap:add:users') ) {      return next(new LDAP.InsufficientAccessRightsError())    }    // make sure the add DN is in the auth_dn    const auth_dn = this.ldap_server.auth_dn()    if ( !auth_dn.parentOf(req.dn) ) {      this.output.warn(`Attempted to perform user insertion on invalid DN: ${req.dn.format(this.configs.get('ldap:server.format'))}`)      return next(new LDAP.InsufficientAccessRightsError())    }    // make sure the user object doesn't already exist    const existing_user = await this.get_resource_from_dn(req.dn)    if ( existing_user ) {      return next(new LDAP.EntryAlreadyExistsError())    }    // build the user object from the request attributes    const req_data = req.toObject().attributes    const register_data = {      first_name: req_data.cn ? req_data.cn[0] : '',      last_name: req_data.sn ? req_data.sn[0] : '',      email: req_data.mail ? req_data.mail[0] : '',      username: req_data.uid ? req_data.uid[0].toLowerCase() : '',      password: req_data.userpassword ? req_data.userpassword[0] : '',    }    // TODO add data fields// from the Starship/CoreID project - app/ldap/controllers/Users.controller.jsconst LDAPController = require('./LDAPController')const LDAP = require('ldapjs')const bcrypt = require('bcrypt')class UsersController extends LDAPController {  static get services() {    return [      ...super.services,      'output',      'ldap_server',      'models',      'configs',      'auth'    ]  }  constructor() {    super()    this.User = this.models.get('auth:User')  }  // Might need to override compare to support special handling for userPassword  // TODO generalize some of the addition logic  // TODO rework some of the registration and validation logic  async add_people(req, res, next) {    const Setting = this.models.get('Setting')    if ( !(await Setting.get('auth.allow_registration')) ) {      return next(new LDAP.InsufficientAccessRightsError('Operation not enabled.'))    }    if ( !req.user.can('ldap:add:users') ) {      return next(new LDAP.InsufficientAccessRightsError())    }    // make sure the add DN is in the auth_dn    const auth_dn = this.ldap_server.auth_dn()    if ( !auth_dn.parentOf(req.dn) ) {      this.output.warn(`Attempted to perform user insertion on invalid DN: ${req.dn.format(this.configs.get('ldap:server.format'))}`)      return next(new LDAP.InsufficientAccessRightsError())    }    // make sure the user object doesn't already exist    const existing_user = await this.get_resource_from_dn(req.dn)    if ( existing_user ) {      return next(new LDAP.EntryAlreadyExistsError())    }    // build the user object from the request attributes    const req_data = req.toObject().attributes    const register_data = {      first_name: req_data.cn ? req_data.cn[0] : '',      last_name: req_data.sn ? req_data.sn[0] : '',      email: req_data.mail ? req_data.mail[0] : '',      username: req_data.uid ? req_data.uid[0].toLowerCase() : '',      password: req_data.userpassword ? req_data.userpassword[0] : '',    }    // TODO add data fields

Hi, there.

My name is Garrett.

I'm a self-taught software developer and speaker.

Hi, there.

My name is Garrett.

I'm a self-taught software developer and speaker.

about me

Hi! My name is Garrett. Welcome to my little corner of the internet. I'm a self-taught developer and tech-nerd. I create software that I hope makes people's lives better. I created the Flitter web framework, and a couple other fun projects. I love to communicate my work, and help others pursue their projects, which is why I've got a long history of sharing about my passion. I write blog posts, create video tutorials, hold talks, and publish code from my projects in the hope that others will find it useful.

A bit more background: I grew up in the rural mid-west, so I taught myself everything I know. I'm a big fan of learning to code this way. I'm currently studying computer science at the University of Kansas.

about me

Hi! My name is Garrett. Welcome to my little corner of the internet. I'm a self-taught developer and tech-nerd. I create software that I hope makes people's lives better. I created the Flitter web framework, and a couple other fun projects. I love to communicate my work, and help others pursue their projects, which is why I've got a long history of sharing about my passion. I write blog posts, create video tutorials, hold talks, and publish code from my projects in the hope that others will find it useful.

A bit more background: I grew up in the rural mid-west, so I taught myself everything I know. I'm a big fan of learning to code this way. I'm currently studying computer science at the University of Kansas.

what I've worked on

2021
January 2021 - Present

Extollo

Extollo is the next iteration of my Flitter project. My goal is to use what I've learned from creating Flitter to create an even better and safer web app framework in Node.js built with Typescript.

The project is very much in the early stages, but so far includes a dependency injector, basic startup framework, and a Typescript-based ORM.

2020
April 2020 - Present

Starship CoreID

I an an avid self-hoster. As such, I have a lot of disparate apps that all have different login schemes, which can be a bit annoying to manage for myself and friends.

So, I decided to build a unified login system similar to things like CAS. CoreID supports OAuth2, OpenID Connect, LDAP, and SAML2 with universal 2FA and granular access controls. This project has taught me a lot about the different SSO stacks.

March 2020 - February 2021

TeraCrunch, LLC

TeraCrunch is a Kansas City-based data analytics and machine learning firm.

I worked with them as a freelance systems engineer to handle infrastructure projects like backups and scheduled jobs, and smaller client projects such as a statistics aggregator, and Node.js application enhancements/maintenance.

February 2020 - February 2020

HackKU 2020

HackKU is the University of Kansas' annual hackathon.

My group participated for the second year where we built Noded, a rich-data note-taking app designed to help people build personal information trees.

I liked this concept so much that I've continued improving it since then, and I use it for my personal notes to this day.

2019
May 2019 - Present

AllofE Solutions

AllofE is a software company in Lawrence, Kansas, primarily focused on the eMedley web suite for higher-education.

I work as a software engineering intern doing full stack development in PHP/SQL/Angular. Of note, I designed and built a new automated proctoring flow used by 10+ schools built on TensorFlow and AWS Lambda. I also helped integrate and transition 50+ models and infrastructure components from a legacy framework to Laravel.

February 2019 - February 2019

HackKU 2019

HackKU is the University of Kansas' annual hackathon.

I participated with a couple friends and we built WaitNoMore, a multi-tenant parking management app built on Python, Firebase, and Flutter.

For this project, we were awarded the Best Implementation of Google Cloud.

2018
August 2018 - Present

Flitter

Flitter is my take on a Node.js app framework.

I started it as a learning project, and have expanded it to act as a base for all of my personal apps. It includes a unit-based startup framework, a dependency injector, an ORM, a job-queue wrapper, an auth framework, and more.

August 2018 - May 2019

Center for Research Methods & Data Analysis

The CRMDA was a University of Kansas lab that assisted researchers with data analysis projects and computing.

I worked as a lab system technician there my freshman year of college maintaining the CentOS lab workstations, transitioning 20+ cluster scripts to the SLURM scheduler, and creating a proof-of-concept Kubernetes cluster on which I help a colloquium.

March 2018 - August 2018

KRS Corporation

The KRS Corporation is an enterprise manufacturer based in my hometown.

I worked there over the summer assembling various components. Of note, I designed an Arduino break-out circuit to automate the flashing of these components. This system reduced the time required to program the controller boards by half.

2017
May 2017 - August 2017

Unified School District #416

USD 416 is the school district in my hometown.

As a summer job, I worked as an IT technician where I helped replace 50+ access points as part of a wireless deployment, imaged 100+ computers using Novell and Active Directory, and assisted with user support.

2016
August 2016 - May 2018

TEDxYouth@Louisburg

For two years, I served as the technical-director of TEDxYouth@Louisburg and helped organize and live-broadcast the first TEDxYouth event at a high-school in Kansas.

Particularly, I helped plan schedules for breakout rooms, built the sign-in and ticketing system, and directed the live-production of the event itself for 150+ guests.

get in touch

I'd love to hear from you if you have questions or inquiries related to me or my projects. You can get in touch by text, e-mail, or using this form. I also tweet sometimes, and share thoughts on my blog.

E-Mail: shout@garrettmills.dev
Phone: (913) 730-7124

I'd love to hear from you if you have questions or inquiries related to me or my projects. You can get in touch by text, e-mail, or using this form. I also tweet sometimes, and share thoughts on my blog.

E-Mail: shout@garrettmills.dev
Phone: (913) 730-7124

latest updates

Side Project

Side Project

New Features in Noded

Noded is a project I started at HackKU last year. It's a rich-data notes app designed to help people create information trees. I've been slowly improving it since.

  • File Box
    • In addition to the basic file uploader, you can now add "File Boxes" to your notes, which support nested structures and managing individual files.
    • Files in File Boxes appear in the universal search, and will open to their nested location directly.
  • Universal Search
    • Nodes that support full-screen mode now open directly from the search interface. This means that the open page is unchanged.
  • WYSIWYG
    • In-line links and images now render properly in view-only mode.
  • Databases
    • Added the "Hyperlink" column type for external links.
    • Added the "Link to Page" column type for referencing other notes.
  • Users can now drag-and-drop to re-order subtrees in the sidebar.

You can try Noded out here.

permalink  |  2/8/2021, 9:39:31 PM

Open Letter

Open Letter

An Open Letter to Senator-elect Roger Marshall

Roger Marshall, Kansas Senator-elect, has expressed his intention to vote not to certify the result of the 2020 presidential election.

I feel very strongly that this is a dangerous and irresponsible move that goes against the core tenets of American democracy.

Read the letter here.

This letter is released in the public domain. Please, adapt it, share it with others, and most importantly, send it to your representatives. Call them, e-mail them, snail mail them to tell them to support free and fair elections.

permalink  |  1/2/2021, 11:30:31 PM

Code Snippet

Code Snippet

Full-text search PDFs from Linux CLI

For an open-note exam, I wanted a quick way to full-text search PDFs from the command-line.

I wrote a 2-line script to help with that, using just find, grep, and pdftotext (common to most distros).

Get it here.

permalink  |  12/9/2020, 1:35:36 AM

Side Project

Side Project

MiniQ: A bare-bones, CRON-driven job queue.

I wanted a simple way to queue jobs to be run in the background without having to run a separate daemon.

MiniQ is what I came up with. With just 3 files, MiniQ provides the ability to log jobs and the CRON script will run periodically and execute the queued jobs in the background.

More info here.

permalink  |  12/2/2020, 7:51:45 PM

Blog Post

Blog Post

Converting an Ionic/Angular Site into a Progressive Web App

For the last year or so, I've been working on converting an Ionic app to a progressive web app with offline support called Noded. I decided to write up my findings on how to do this with Angular service-worker.

Read more about it here.

permalink  |  12/1/2020, 6:28:31 PM

Side Project

Side Project

My Technical Notes Site

I'm trying to write down or save all the technical tricks, notes, and fixes I find. That way, it's easier for me to find them again in the future, and maybe they can be of use to others.

You can check them out here.

permalink  |  11/29/2020, 9:13:30 AM

Garrett Mills
Copyright © 2021 Garrett Mills