Skip to content

Commit

Permalink
Merge pull request #69 from woodjme/v3-beta
Browse files Browse the repository at this point in the history
v3 release
  • Loading branch information
woodjme authored Jun 27, 2024
2 parents 3b71670 + f7ce125 commit b069db6
Show file tree
Hide file tree
Showing 44 changed files with 7,149 additions and 3,000 deletions.
11 changes: 11 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
UNIFI_USER=
UNIFI_PASS=
UNIFI_CONTROLLER_URL=
UNIFI_SITE_IDENTIFIER=default
SESSION_SECRET=secretString
AUTH=simple
REDIRECTURL=https://guestgate.cloud
PORT=80
LOG_AUTH_DRIVER=none
LOG_LEVEL=info
NODE_ENV=production
44 changes: 22 additions & 22 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
{
"env": {
"commonjs": true,
"es6": true,
"node": true
},
"extends": [
"standard",
"plugin:jest/recommended"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 13
},
"rules": {
"jest/no-test-callback": 0
},
"plugins": [
"jest"
]
"env": {
"commonjs": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"plugin:jest/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 13,
"sourceType": "module",
"project": "./tsconfig.json"
},
"rules": {
"prettier/prettier": "error",
"jest/no-test-callback": 0
},
"plugins": ["jest", "prettier", "@typescript-eslint"]
}
17 changes: 6 additions & 11 deletions .github/workflows/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,21 @@ jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
- name: Checkout
uses: actions/checkout@v3
-
name: Set up QEMU
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Login to DockerHub
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
- name: Build and push
uses: docker/build-push-action@v3
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: woodjme/unifi-hotspot:dev
tags: woodjme/unifi-hotspot:dev
18 changes: 6 additions & 12 deletions .github/workflows/tags.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
- name: Checkout
uses: actions/checkout@v3
-
name: Docker meta
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
Expand All @@ -28,21 +26,17 @@ jobs:
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
-
name: Set up QEMU
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Login to DockerHub
- name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
- name: Build and push
uses: docker/build-push-action@v3
with:
context: .
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ docs/.vuepress/dist
docs/.vuepress/.cache
docs/.vuepress/.temp

dist/
1 change: 1 addition & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx --no -- commitlint --edit $1
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx lint-staged
5 changes: 5 additions & 0 deletions .huskyrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"hooks": {
"pre-commit": "lint-staged"
}
}
4 changes: 4 additions & 0 deletions .lintstagedrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"*/**/*.{js,jsx,ts,tsx}": ["prettier --write"],
"*/**/*.{json,css,md}": ["prettier --write"]
}
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package-lock.json
node_modules
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"endOfLine": "lf"
}
19 changes: 14 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
FROM node:18-alpine
FROM node:20-alpine as build

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package*.json ./
RUN npm ci --omit=dev
RUN npm install
COPY . .

# Bundle app source
COPY . /usr/src/app
RUN npm run build

FROM node:20-alpine

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --only=production

COPY --from=build /usr/src/app/dist /usr/src/app/

#Expose Port
EXPOSE 4545

#Start
CMD [ "npm", "start" ]
CMD [ "node", "index.js" ]
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
# unifi-hotspot

The purpose of this repo is to provide a flexible, Node.js based external portal server for authorising Wi-Fi guests on Unifi products. Out of the box is currently support storing user information in Google Sheets or posting it via a webhook.
This repository hosts a versatile external captive portal server designed for authorizing Wi-Fi guests on Unifi products. The application supports flexible user data storage solutions, including integration with Google Sheets and webhooks, making it ideal for various deployment scenarios.

## What's new in V2
> **Exciting News!**
>
> Coming soon! Simplify your experience with our upcoming hosted version of this application. Perfect for those who prefer a hassle-free setup or are willing to pay a premium for a managed solution. Don't miss out on early access—sign up now [here](https://guestgate.cloud)!
### BREAKING CHANGES
## What's New in V3

* The `USERNAME` environment variable has been renamed to `UNIFI_USER`
* The `PASSWORD` environment variable has been renamed to `UNIFI_PASS`
* Changed `basic` value for `AUTH_ENV` to `userInfo`
### Breaking Changes

- The `URI` environment variable has been renamed to `UNIFI_CONTROLLER_URL`.
- The `SITENAME` environment variable has been renamed to `UNIFI_SITE_IDENTIFIER`.
- The `LOG_AUTH_GOOGLE_SERVICE_ACCOUNT_EMAIL` and `LOG_AUTH_GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY` environment variables have been replaced with `LOG_AUTH_GOOGLE_CREDENTIALS`.

### Features and Improvements

* Bumped to NodeJS Version 18
* Removed `request` and `request-promise` packages in favour of `axios`
* Rewritten authorisation controller
* 🎉 Store the contents of the hotspot form using `LOG_AUTH` drivers 🎉
* Listen on port given in env
- Added support for devices with built-in controllers such as the Unifi Dream Machine.
- Upgraded to NodeJS Version 20.
- Codebase rewritten in Typescript.

## Documentation

[Documentation](https://docs.unifi-hotspot.jamiewood.io)
For detailed information on how to set up and use this application, please refer to the [Documentation](https://docs.unifi-hotspot.jamiewood.io).
42 changes: 23 additions & 19 deletions __tests__/routes/basicauth.test.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
const request = require('supertest')
const app = require('../../src/server')
const request = require('supertest');
const app = require('../../src/server');

describe('get /guest/s/process.env.UNIFI_SITENAME/ with basic auth', () => {
const OLD_ENV = process.env
const OLD_ENV = process.env;

beforeEach(() => {
jest.resetModules()
process.env = { ...OLD_ENV }
delete process.env.NODE_ENV
process.env.AUTH = 'basic'
})
jest.resetModules();
process.env = {
...OLD_ENV,
};
delete process.env.NODE_ENV;
process.env.AUTH = 'basic';
});

afterEach(() => {
process.env = OLD_ENV
})
process.env = OLD_ENV;
});

it('should return a 200', async () => {
const res = await request(app)
.get(`/guest/s/${process.env.UNIFI_SITENAME}/`)
expect(res.statusCode).toEqual(200)
})
const res = await request(app).get(
`/guest/s/${process.env.UNIFI_SITENAME}/`,
);
expect(res.statusCode).toEqual(200);
});

it('should return the noAuth page', async () => {
const res = await request(app)
.get(`/guest/s/${process.env.UNIFI_SITENAME}/`)
expect(res.text).toContain('<title>Portal Page - Basic Auth</title>')
})
})
const res = await request(app).get(
`/guest/s/${process.env.UNIFI_SITENAME}/`,
);
expect(res.text).toContain('<title>Portal Page - Basic Auth</title>');
});
});
22 changes: 10 additions & 12 deletions __tests__/routes/gets.test.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
const request = require('supertest')
const app = require('../../src/server')
const request = require('supertest');
const app = require('../../src/server');

describe('get /', () => {
it('should return a 301', async () => {
const res = await request(app)
.get('/')
expect(res.statusCode).toEqual(301)
})
})
const res = await request(app).get('/');
expect(res.statusCode).toEqual(301);
});
});

describe('get randomPage', () => {
it('should return a 404', async () => {
const res = await request(app)
.get(`/${Math.floor(Math.random() * 10)}`)
expect(res.statusCode).toEqual(404)
})
})
const res = await request(app).get(`/${Math.floor(Math.random() * 10)}`);
expect(res.statusCode).toEqual(404);
});
});
38 changes: 19 additions & 19 deletions __tests__/routes/noauth.test.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
const request = require('supertest')
const app = require('../../src/server')
const request = require('supertest');
const app = require('../../src/server');

describe('get /guest/s/process.env.SITENAME/ with no auth', () => {
const OLD_ENV = process.env
const OLD_ENV = process.env;

beforeEach(() => {
jest.resetModules()
process.env = { ...OLD_ENV }
delete process.env.NODE_ENV
process.env.AUTH = 'none'
})
jest.resetModules();
process.env = {
...OLD_ENV,
};
delete process.env.NODE_ENV;
process.env.AUTH = 'none';
});

afterEach(() => {
process.env = OLD_ENV
})
process.env = OLD_ENV;
});

it('should return a 200', async () => {
const res = await request(app)
.get(`/guest/s/${process.env.SITENAME}/`)
expect(res.statusCode).toEqual(200)
})
const res = await request(app).get(`/guest/s/${process.env.SITENAME}/`);
expect(res.statusCode).toEqual(200);
});

it('should return the noAuth page', async () => {
const res = await request(app)
.get(`/guest/s/${process.env.SITENAME}/`)
expect(res.text).toContain('<title>Portal Page - No Auth</title>')
})
})
const res = await request(app).get(`/guest/s/${process.env.SITENAME}/`);
expect(res.text).toContain('<title>Portal Page - No Auth</title>');
});
});
1 change: 1 addition & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = { extends: ['@commitlint/config-conventional'] };
18 changes: 10 additions & 8 deletions docs/.vuepress/config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
module.exports = {
import { viteBundler } from '@vuepress/bundler-vite';
import { defaultTheme } from '@vuepress/theme-default';
import { defineUserConfig } from 'vuepress';

export default defineUserConfig({
title: 'Unifi Hotspot',
base: '/',
themeConfig: {
displayAllHeaders: true,
lang: 'en-GB',
bundler: viteBundler(),
theme: defaultTheme({
sidebarDepth: 5,
sidebar: [
'/',
]
}
}
}),
});
Loading

0 comments on commit b069db6

Please sign in to comment.