Compare commits

...

14 Commits
0.8.0 ... 0.8.4

Author SHA1 Message Date
Lakhan Samani
2d819f5d3c Update app 2022-01-08 23:01:52 +05:30
Lakhan Samani
3221740198 Fix issue with reset password 2022-01-08 23:01:06 +05:30
Lakhan Samani
1e759c64ed Fix email template 2022-01-08 18:44:19 +05:30
Lakhan Samani
b3c7f783ed Update tests 2022-01-08 18:16:26 +05:30
Lakhan Samani
37fe5071c5 Use gomail library for sending emails
3b881776b5
2022-01-08 14:08:42 +05:30
Lakhan Samani
2137d8ef5d Merge pull request #96 from authorizerdev/fix/smtp-send-mail
fix: send mail from param
2022-01-07 21:40:52 +05:30
Lakhan Samani
8178fa6b62 fix: send mail from param 2022-01-07 21:40:28 +05:30
Lakhan Samani
303a3cbbbe Merge pull request #95 from authorizerdev/smtp-improvements
Improve smtp variable names
2022-01-07 19:32:20 +05:30
Lakhan Samani
9173b340c8 Improve smtp variable names
_Rename:_

- `SENDER_EMAIL` -> `SMTP_USERNAME`
- `SENDER_PASSWORD` -> `SMTP_PASSWORD`
- `SENDER_EMAIL` -> Used as `From` in email

Resolves #94
2022-01-07 19:29:22 +05:30
Lakhan Samani
df192bed4d feat: allow disabling login page
Resolves #89
2021-12-29 05:41:39 +05:30
Lakhan Samani
8d2371c14e fix: spacing 2021-12-29 05:21:24 +05:30
Lakhan Samani
5ed669e0da Merge pull request #88 from authorizerdev/fix/app-code-spliting
Fix/app code spliting
2021-12-29 05:19:20 +05:30
Lakhan Samani
43dce69cce fix: update build script 2021-12-29 05:10:21 +05:30
Lakhan Samani
4c53eb97d2 fix: enable code spliting for app 2021-12-29 04:16:31 +05:30
27 changed files with 267 additions and 460 deletions

View File

@@ -7,3 +7,5 @@ ROADMAP.md
build
.env
data.db
app/node_modules
app/build

View File

@@ -3,8 +3,9 @@ DATABASE_URL=data.db
DATABASE_TYPE=sqlite
ADMIN_SECRET=admin
JWT_SECRET=random_string
SENDER_EMAIL=username
SENDER_PASSWORD=password
SENDER_EMAIL=info@authorizer.dev
SMTP_USERNAME=username
SMTP_PASSWORD=password
SMTP_HOST=smtp.mailtrap.io
SMTP_PORT=2525
JWT_TYPE=HS256

View File

@@ -8,26 +8,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
- uses: actions/setup-go@v2
with:
go-version: '^1.17.3'
- name: Install dependencies
run: |
sudo apt-get install build-essential wget zip gcc-mingw-w64 && \
sudo apt-get remove --auto-remove golang-go && \
sudo rm -rf /usr/bin/go &&\
wget --progress=dot:mega https://golang.org/dl/go1.17.1.linux-amd64.tar.gz -O go-linux.tar.gz && \
sudo tar -zxf go-linux.tar.gz && \
sudo mv go /usr/bin/ && \
sudo mkdir -p /go/bin /go/src /go/pkg && \
export GO_HOME=/usr/bin/go && \
export GOPATH=/go && \
export PATH=${GOPATH}/bin:${GO_HOME}/bin/:$PATH && \
echo "/usr/bin/go/bin" >> $GITHUB_PATH
echo "/usr/bin/x86_64-w64-mingw32-gcc" >> GITHUB_PATH
go version && \
echo "/usr/bin/x86_64-w64-mingw32-gcc" >> GITHUB_PATH && \
wget --no-check-certificate --progress=dot:mega https://github.com/wangyoucao577/assets-uploader/releases/download/v0.3.0/github-assets-uploader-v0.3.0-linux-amd64.tar.gz -O github-assets-uploader.tar.gz && \
tar -zxf github-assets-uploader.tar.gz && \
sudo mv github-assets-uploader /usr/sbin/ && \
sudo rm -f github-assets-uploader.tar.gz && \
github-assets-uploader -version
github-assets-uploader -version && \
make build-app
- name: Print Go paths
run: whereis go
- name: Print Go Version

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@ server/server
server/.env
data
app/node_modules
app/build
build
.env
data.db

View File

@@ -1,5 +1,5 @@
FROM golang:1.17-alpine as builder
WORKDIR /app
FROM golang:1.17-alpine as go-builder
WORKDIR /authorizer
COPY server server
COPY Makefile .
@@ -7,15 +7,22 @@ ARG VERSION="latest"
ENV VERSION="$VERSION"
RUN echo "$VERSION"
RUN apk add build-base nodejs &&\
RUN apk add build-base &&\
make clean && make && \
chmod 777 build/server
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
FROM node:17-alpine3.12 as node-builder
WORKDIR /authorizer
COPY app app
COPY Makefile .
RUN apk add build-base &&\
make build-app
FROM alpine:latest
WORKDIR /root/
RUN mkdir app
COPY --from=node-builder /authorizer/app/build app/build
COPY --from=go-builder /authorizer/build build
COPY templates templates
COPY --from=builder /app/build build
EXPOSE 8080
CMD [ "./build/server" ]

View File

@@ -3,6 +3,8 @@ VERSION := $(or $(VERSION),$(DEFAULT_VERSION))
cmd:
cd server && go build -ldflags "-w -X main.VERSION=$(VERSION)" -o '../build/server'
build-app:
cd app && npm i && npm run build
clean:
rm -rf build
test:

View File

@@ -1,16 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #374151;
font-size: 14px;
}
*,
*:before,
*:after {
box-sizing: inherit;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

11
app/esbuild.config.js Normal file
View File

@@ -0,0 +1,11 @@
const __is_prod__ = process.env.NODE_ENV === 'production';
require('esbuild').build({
entryPoints: ['src/index.tsx'],
chunkNames: '[name]-[hash]',
bundle: true,
minify: __is_prod__,
outdir: 'build',
splitting: true,
format: 'esm',
watch: !__is_prod__,
});

150
app/package-lock.json generated
View File

@@ -13,9 +13,9 @@
}
},
"@authorizerdev/authorizer-react": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.3.0.tgz",
"integrity": "sha512-9f0cREXz2ND1wkgAxBV6YenjSSkhlzE79ExMdmcjZhRs0+htiF3YBNDTY4OGqL/lH+9SEsSxCjM/mttHak1nmQ==",
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.4.0.tgz",
"integrity": "sha512-ydE7xrP3cqeTtU923bK0+OIB1fnL0VHnbThcNa41n89XUPV3VBhZ23gxMg90nqon8JFE5g2TNz7+/qBCOQ7aZw==",
"requires": {
"@authorizerdev/authorizer-js": "^0.2.0",
"final-form": "^4.20.2",
@@ -24,100 +24,100 @@
}
},
"@babel/code-frame": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz",
"integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
"integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
"requires": {
"@babel/highlight": "^7.16.0"
"@babel/highlight": "^7.16.7"
}
},
"@babel/generator": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.5.tgz",
"integrity": "sha512-kIvCdjZqcdKqoDbVVdt5R99icaRtrtYhYK/xux5qiWCBmfdvEYMFZ68QCrpE5cbFM1JsuArUNs1ZkuKtTtUcZA==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.7.tgz",
"integrity": "sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg==",
"requires": {
"@babel/types": "^7.16.0",
"@babel/types": "^7.16.7",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
},
"@babel/helper-annotate-as-pure": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz",
"integrity": "sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz",
"integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==",
"requires": {
"@babel/types": "^7.16.0"
"@babel/types": "^7.16.7"
}
},
"@babel/helper-environment-visitor": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz",
"integrity": "sha512-ODQyc5AnxmZWm/R2W7fzhamOk1ey8gSguo5SGvF0zcB3uUzRpTRmM/jmLSm9bDMyPlvbyJ+PwPEK0BWIoZ9wjg==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz",
"integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==",
"requires": {
"@babel/types": "^7.16.0"
"@babel/types": "^7.16.7"
}
},
"@babel/helper-function-name": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz",
"integrity": "sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
"integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==",
"requires": {
"@babel/helper-get-function-arity": "^7.16.0",
"@babel/template": "^7.16.0",
"@babel/types": "^7.16.0"
"@babel/helper-get-function-arity": "^7.16.7",
"@babel/template": "^7.16.7",
"@babel/types": "^7.16.7"
}
},
"@babel/helper-get-function-arity": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz",
"integrity": "sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz",
"integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==",
"requires": {
"@babel/types": "^7.16.0"
"@babel/types": "^7.16.7"
}
},
"@babel/helper-hoist-variables": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz",
"integrity": "sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
"integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
"requires": {
"@babel/types": "^7.16.0"
"@babel/types": "^7.16.7"
}
},
"@babel/helper-module-imports": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz",
"integrity": "sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
"integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
"requires": {
"@babel/types": "^7.16.0"
"@babel/types": "^7.16.7"
}
},
"@babel/helper-split-export-declaration": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz",
"integrity": "sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
"integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
"requires": {
"@babel/types": "^7.16.0"
"@babel/types": "^7.16.7"
}
},
"@babel/helper-validator-identifier": {
"version": "7.15.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
"integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="
},
"@babel/highlight": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz",
"integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz",
"integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==",
"requires": {
"@babel/helper-validator-identifier": "^7.15.7",
"@babel/helper-validator-identifier": "^7.16.7",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.16.6",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.6.tgz",
"integrity": "sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ=="
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz",
"integrity": "sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA=="
},
"@babel/runtime": {
"version": "7.14.8",
@@ -128,38 +128,38 @@
}
},
"@babel/template": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz",
"integrity": "sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
"integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
"requires": {
"@babel/code-frame": "^7.16.0",
"@babel/parser": "^7.16.0",
"@babel/types": "^7.16.0"
"@babel/code-frame": "^7.16.7",
"@babel/parser": "^7.16.7",
"@babel/types": "^7.16.7"
}
},
"@babel/traverse": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.5.tgz",
"integrity": "sha512-FOCODAzqUMROikDYLYxl4nmwiLlu85rNqBML/A5hKRVXG2LV8d0iMqgPzdYTcIpjZEBB7D6UDU9vxRZiriASdQ==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.7.tgz",
"integrity": "sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ==",
"requires": {
"@babel/code-frame": "^7.16.0",
"@babel/generator": "^7.16.5",
"@babel/helper-environment-visitor": "^7.16.5",
"@babel/helper-function-name": "^7.16.0",
"@babel/helper-hoist-variables": "^7.16.0",
"@babel/helper-split-export-declaration": "^7.16.0",
"@babel/parser": "^7.16.5",
"@babel/types": "^7.16.0",
"@babel/code-frame": "^7.16.7",
"@babel/generator": "^7.16.7",
"@babel/helper-environment-visitor": "^7.16.7",
"@babel/helper-function-name": "^7.16.7",
"@babel/helper-hoist-variables": "^7.16.7",
"@babel/helper-split-export-declaration": "^7.16.7",
"@babel/parser": "^7.16.7",
"@babel/types": "^7.16.7",
"debug": "^4.1.0",
"globals": "^11.1.0"
}
},
"@babel/types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz",
"integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz",
"integrity": "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==",
"requires": {
"@babel/helper-validator-identifier": "^7.15.7",
"@babel/helper-validator-identifier": "^7.16.7",
"to-fast-properties": "^2.0.0"
}
},
@@ -490,9 +490,9 @@
},
"dependencies": {
"@babel/runtime": {
"version": "7.16.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz",
"integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
"requires": {
"regenerator-runtime": "^0.13.4"
}

View File

@@ -4,13 +4,14 @@
"description": "",
"main": "index.js",
"scripts": {
"build": "esbuild src/index.tsx --bundle --minify --sourcemap --outfile=build/bundle.js"
"build": "rm -rf build && NODE_ENV=production node ./esbuild.config.js",
"start": "NODE_ENV=development node ./esbuild.config.js"
},
"keywords": [],
"author": "Lakhan Samani",
"license": "ISC",
"dependencies": {
"@authorizerdev/authorizer-react": "^0.3.0",
"@authorizerdev/authorizer-react": "latest",
"@types/react": "^17.0.15",
"@types/react-dom": "^17.0.9",
"esbuild": "^0.12.17",

View File

@@ -1,9 +1,10 @@
import React, { useEffect } from 'react';
import React, { useEffect, lazy, Suspense } from 'react';
import { Switch, Route } from 'react-router-dom';
import { useAuthorizer } from '@authorizerdev/authorizer-react';
import Dashboard from './pages/dashboard';
import Login from './pages/login';
import ResetPassword from './pages/rest-password';
const ResetPassword = lazy(() => import('./pages/rest-password'));
const Login = lazy(() => import('./pages/login'));
const Dashboard = lazy(() => import('./pages/dashboard'));
export default function Root() {
const { token, loading, config } = useAuthorizer();
@@ -24,15 +25,18 @@ export default function Root() {
if (token) {
return (
<Suspense fallback={<></>}>
<Switch>
<Route path="/app" exact>
<Dashboard />
</Route>
</Switch>
</Suspense>
);
}
return (
<Suspense fallback={<></>}>
<Switch>
<Route path="/app" exact>
<Login />
@@ -41,5 +45,6 @@ export default function Root() {
<ResetPassword />
</Route>
</Switch>
</Suspense>
);
}

16
app/src/index.css Normal file
View File

@@ -0,0 +1,16 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #374151;
font-size: 14px;
}
*,
*:before,
*:after {
box-sizing: inherit;
}

View File

@@ -1,5 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
ReactDOM.render(<App />, document.getElementById('root'));

View File

@@ -1,5 +1,5 @@
VERSION="$1"
make clean && CGO_ENABLED=1 VERSION=${VERSION} make
make clean && make build-app && CGO_ENABLED=1 VERSION=${VERSION} make
FILE_NAME=authorizer-${VERSION}-darwin-amd64.tar.gz
tar cvfz ${FILE_NAME} .env app/build build templates
AUTH="Authorization: token $GITHUB_TOKEN"

View File

@@ -2,8 +2,10 @@ package test
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"time"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
@@ -66,7 +68,7 @@ func createContext(s TestSetup) (*http.Request, context.Context) {
func testSetup() TestSetup {
testData := TestData{
Email: "authorizer_tester@yopmail.com",
Email: fmt.Sprintf("%d_authorizer_tester@yopmail.com", time.Now().Unix()),
Password: "test",
}

View File

@@ -11,8 +11,9 @@ var (
DATABASE_NAME = ""
SMTP_HOST = ""
SMTP_PORT = ""
SMTP_USERNAME = ""
SMTP_PASSWORD = ""
SENDER_EMAIL = ""
SENDER_PASSWORD = ""
JWT_TYPE = ""
JWT_SECRET = ""
ALLOWED_ORIGINS = []string{}
@@ -26,6 +27,7 @@ var (
DISABLE_EMAIL_VERIFICATION = false
DISABLE_BASIC_AUTHENTICATION = false
DISABLE_MAGIC_LINK_LOGIN = false
DISABLE_LOGIN_PAGE = false
// ROLES
ROLES = []string{}

View File

@@ -1,90 +1,28 @@
package email
import (
"bytes"
"fmt"
"crypto/tls"
"log"
"mime/quotedprintable"
"net/smtp"
"strings"
"strconv"
"github.com/authorizerdev/authorizer/server/constants"
gomail "gopkg.in/mail.v2"
)
/**
Using: https://github.com/tangingw/go_smtp/blob/master/send_mail.go
For gmail add instruction to enable less security
// https://myaccount.google.com/u/0/lesssecureapps
// https://www.google.com/settings/security/lesssecureapps
// https://stackoverflow.com/questions/19877246/nodemailer-with-gmail-and-nodejs
**/
// TODO -> try using gomail.v2
type Sender struct {
User string
Password string
}
func NewSender() Sender {
return Sender{User: constants.SENDER_EMAIL, Password: constants.SENDER_PASSWORD}
}
func (sender Sender) SendMail(Dest []string, Subject, bodyMessage string) error {
msg := "From: " + sender.User + "\n" +
"To: " + strings.Join(Dest, ",") + "\n" +
"Subject: " + Subject + "\n" + bodyMessage
err := smtp.SendMail(constants.SMTP_HOST+":"+constants.SMTP_PORT,
smtp.PlainAuth("", sender.User, sender.Password, constants.SMTP_HOST),
sender.User, Dest, []byte(msg))
if err != nil {
func SendMail(to []string, Subject, bodyMessage string) error {
m := gomail.NewMessage()
m.SetHeader("From", constants.SENDER_EMAIL)
m.SetHeader("To", to...)
m.SetHeader("Subject", Subject)
m.SetBody("text/html", bodyMessage)
port, _ := strconv.Atoi(constants.SMTP_PORT)
d := gomail.NewDialer(constants.SMTP_HOST, port, constants.SMTP_USERNAME, constants.SMTP_PASSWORD)
if constants.ENV == "development" {
d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
}
if err := d.DialAndSend(m); err != nil {
log.Printf("smtp error: %s", err)
return err
}
return nil
}
func (sender Sender) WriteEmail(dest []string, contentType, subject, bodyMessage string) string {
header := make(map[string]string)
header["From"] = sender.User
receipient := ""
for _, user := range dest {
receipient = receipient + user
}
header["To"] = receipient
header["Subject"] = subject
header["MIME-Version"] = "1.0"
header["Content-Type"] = fmt.Sprintf("%s; charset=\"utf-8\"", contentType)
header["Content-Transfer-Encoding"] = "quoted-printable"
header["Content-Disposition"] = "inline"
message := ""
for key, value := range header {
message += fmt.Sprintf("%s: %s\r\n", key, value)
}
var encodedMessage bytes.Buffer
finalMessage := quotedprintable.NewWriter(&encodedMessage)
finalMessage.Write([]byte(bodyMessage))
finalMessage.Close()
message += "\r\n" + encodedMessage.String()
return message
}
func (sender *Sender) WriteHTMLEmail(dest []string, subject, bodyMessage string) string {
return sender.WriteEmail(dest, "text/html", subject, bodyMessage)
}
func (sender *Sender) WritePlainEmail(dest []string, subject, bodyMessage string) string {
return sender.WriteEmail(dest, "text/plain", subject, bodyMessage)
}

15
server/env/env.go vendored
View File

@@ -94,12 +94,16 @@ func InitEnv() {
constants.SMTP_PORT = os.Getenv("SMTP_PORT")
}
if constants.SENDER_EMAIL == "" {
constants.SENDER_EMAIL = os.Getenv("SENDER_EMAIL")
if constants.SMTP_USERNAME == "" {
constants.SMTP_USERNAME = os.Getenv("SMTP_USERNAME")
}
if constants.SENDER_PASSWORD == "" {
constants.SENDER_PASSWORD = os.Getenv("SENDER_PASSWORD")
if constants.SMTP_PASSWORD == "" {
constants.SMTP_PASSWORD = os.Getenv("SMTP_PASSWORD")
}
if constants.SENDER_EMAIL == "" {
constants.SENDER_EMAIL = os.Getenv("SENDER_EMAIL")
}
if constants.JWT_SECRET == "" {
@@ -172,8 +176,9 @@ func InitEnv() {
constants.DISABLE_BASIC_AUTHENTICATION = os.Getenv("DISABLE_BASIC_AUTHENTICATION") == "true"
constants.DISABLE_EMAIL_VERIFICATION = os.Getenv("DISABLE_EMAIL_VERIFICATION") == "true"
constants.DISABLE_MAGIC_LINK_LOGIN = os.Getenv("DISABLE_MAGIC_LINK_LOGIN") == "true"
constants.DISABLE_LOGIN_PAGE = os.Getenv("DISABLE_LOGIN_PAGE") == "true"
if constants.SMTP_HOST == "" || constants.SENDER_EMAIL == "" || constants.SENDER_PASSWORD == "" {
if constants.SMTP_HOST == "" || constants.SMTP_USERNAME == "" || constants.SMTP_PASSWORD == "" || constants.SENDER_EMAIL == "" {
constants.DISABLE_EMAIL_VERIFICATION = true
constants.DISABLE_MAGIC_LINK_LOGIN = true
}

View File

@@ -29,6 +29,8 @@ require (
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/mail.v2 v2.3.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/driver/mysql v1.2.1
gorm.io/driver/postgres v1.2.3

View File

@@ -672,6 +672,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
@@ -679,6 +681,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk=
gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/readline.v1 v1.0.0-20160726135117-62c6fe619375/go.mod h1:lNEQeAhU009zbRxng+XOj5ITVgY24WcbNnQopyfKoYQ=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=

View File

@@ -32,8 +32,9 @@ func main() {
router := router.InitRouter()
// login wall app related routes.
// login page app related routes.
// if we put them in router file then tests would fail as templates or build path will be different
if !constants.DISABLE_LOGIN_PAGE {
router.LoadHTMLGlob("templates/*")
app := router.Group("/app")
{
@@ -41,5 +42,7 @@ func main() {
app.GET("/", handlers.AppHandler())
app.GET("/reset-password", handlers.AppHandler())
}
}
router.Run(":" + constants.PORT)
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"strings"
"time"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
@@ -47,6 +48,12 @@ func ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model
}
user.SignupMethods = signupMethod
// helpful if user has not signed up with basic auth
if user.EmailVerifiedAt == nil {
now := time.Now().Unix()
user.EmailVerifiedAt = &now
}
// delete from verification table
db.Mgr.DeleteVerificationRequest(verificationRequest)
db.Mgr.UpdateUser(user)

View File

@@ -1,7 +1,9 @@
package utils
import (
"fmt"
"bytes"
"encoding/json"
"html/template"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/email"
@@ -9,16 +11,13 @@ import (
// SendVerificationMail to send verification email
func SendVerificationMail(toEmail, token string) error {
sender := email.NewSender()
// The receiver needs to be in slice as the receive supports multiple receiver
Receiver := []string{toEmail}
Subject := "Please verify your email"
message := fmt.Sprintf(`
message := `
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
@@ -41,7 +40,6 @@ func SendVerificationMail(toEmail, token string) error {
</xml>
<![endif]-->
</head>
<body style="font-family: sans-serif;">
<div class="es-wrapper-color">
<!--[if gte mso 9]>
@@ -68,14 +66,15 @@ func SendVerificationMail(toEmail, token string) error {
<table width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank"><img src="%s" alt="icon" style="display: block;" title="icon" width="30"></a></td>
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.OrgLogo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
</tr>
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
<p>Hey there 👋</p>
<p>We received a request to sign-up / login for <b>%s</b>. If this is correct, please confirm your email address by clicking the button below.</p> <br/>
<a href="%s" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Confirm Email</a>
<p>We have received request to verify email for <b>{{.OrgName}}</b>. If this is correct, please confirm your email address by clicking the button below.</p> <br/>
<a
clicktracking="off" href="{{.AuthUrl}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Confirm Email</a>
</td>
</tr>
</tbody>
@@ -100,10 +99,15 @@ func SendVerificationMail(toEmail, token string) error {
<div style="position: absolute; left: -9999px; top: -9999px; margin: 0px;"></div>
</body>
</html>
`, constants.ORGANIZATION_LOGO, constants.ORGANIZATION_NAME, constants.AUTHORIZER_URL+"/verify_email"+"?token="+token)
bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
`
data := make(map[string]interface{}, 3)
data["OrgLogo"] = constants.ORGANIZATION_LOGO
data["OrgName"] = constants.ORGANIZATION_NAME
data["AuthUrl"] = constants.AUTHORIZER_URL + "/verify_email?token=" + token
message = AddEmailTemplate(message, data, "verify_email.tmpl")
// bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
return sender.SendMail(Receiver, Subject, bodyMessage)
return email.SendMail(Receiver, Subject, message)
}
// SendForgotPasswordMail to send verification email
@@ -112,17 +116,14 @@ func SendForgotPasswordMail(toEmail, token, host string) error {
constants.RESET_PASSWORD_URL = constants.AUTHORIZER_URL + "/app/reset-password"
}
sender := email.NewSender()
// The receiver needs to be in slice as the receive supports multiple receiver
Receiver := []string{toEmail}
Subject := "Reset Password"
message := fmt.Sprintf(`
message := `
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
@@ -145,7 +146,6 @@ func SendForgotPasswordMail(toEmail, token, host string) error {
</xml>
<![endif]-->
</head>
<body style="font-family: sans-serif;">
<div class="es-wrapper-color">
<!--[if gte mso 9]>
@@ -172,14 +172,14 @@ func SendForgotPasswordMail(toEmail, token, host string) error {
<table width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank"><img src="%s" alt="icon" style="display: block;" title="icon" width="30"></a></td>
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.OrgLogo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
</tr>
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
<p>Hey there 👋</p>
<p>We received a request to reset password for email: <b>%s</b>. If this is correct, please reset the password clicking the button below.</p> <br/>
<a href="%s" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Reset Password</a>
<p>We have received a request to reset password for email: <b>{{.ToEmail}}</b>. If this is correct, please reset the password clicking the button below.</p> <br/>
<a clicktracking="off" href="{{.AuthUrl}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Reset Password</a>
</td>
</tr>
</tbody>
@@ -204,9 +204,28 @@ func SendForgotPasswordMail(toEmail, token, host string) error {
<div style="position: absolute; left: -9999px; top: -9999px; margin: 0px;"></div>
</body>
</html>
`, constants.ORGANIZATION_LOGO, toEmail, constants.RESET_PASSWORD_URL+"?token="+token)
`
bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
data := make(map[string]interface{}, 3)
data["OrgLogo"] = constants.ORGANIZATION_LOGO
data["ToEmail"] = constants.ORGANIZATION_NAME
data["AuthUrl"] = constants.RESET_PASSWORD_URL + "?token=" + token
message = AddEmailTemplate(message, data, "reset_password_email.tmpl")
return sender.SendMail(Receiver, Subject, bodyMessage)
return email.SendMail(Receiver, Subject, message)
}
func AddEmailTemplate(a string, b map[string]interface{}, templateName string) string {
tmpl, err := template.New(templateName).Parse(a)
if err != nil {
output, _ := json.Marshal(b)
return string(output)
}
buf := &bytes.Buffer{}
err = tmpl.Execute(buf, b)
if err != nil {
panic(err)
}
s := buf.String()
return s
}

View File

@@ -5,13 +5,13 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="/app/build/bundle.css">
<link rel="stylesheet" href="/app/build/index.css">
<script>
window.__authorizer__ = {{.data}}
</script>
</head>
<body>
<div id="root"></div>
<script src="/app/build/bundle.js"></script>
<script type="module" src="/app/build/index.js"></script>
</body>
</html>