Compare commits
41 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3d75a4a281 | ||
![]() |
2d819f5d3c | ||
![]() |
3221740198 | ||
![]() |
1e759c64ed | ||
![]() |
b3c7f783ed | ||
![]() |
37fe5071c5 | ||
![]() |
2137d8ef5d | ||
![]() |
8178fa6b62 | ||
![]() |
303a3cbbbe | ||
![]() |
9173b340c8 | ||
![]() |
df192bed4d | ||
![]() |
8d2371c14e | ||
![]() |
5ed669e0da | ||
![]() |
43dce69cce | ||
![]() |
4c53eb97d2 | ||
![]() |
b4b8593879 | ||
![]() |
46a91fde20 | ||
![]() |
8f826e6c2f | ||
![]() |
ebfea707c5 | ||
![]() |
8fc0175166 | ||
![]() |
dc43f56db1 | ||
![]() |
e5761f1e42 | ||
![]() |
8dd8252a46 | ||
![]() |
7ee4715af2 | ||
![]() |
1b3f931074 | ||
![]() |
30cde3e521 | ||
![]() |
6e9370458b | ||
![]() |
beae4502d4 | ||
![]() |
969395ccdb | ||
![]() |
3ee79c3937 | ||
![]() |
508c714932 | ||
![]() |
8f7582e1ec | ||
![]() |
bdbbe4adee | ||
![]() |
65478296cb | ||
![]() |
2342f7c5c6 | ||
![]() |
8266c1cff5 | ||
![]() |
c662c625a0 | ||
![]() |
c989648327 | ||
![]() |
a933ac1118 | ||
![]() |
b8afe7abcc | ||
![]() |
3ab02cc4ff |
@@ -7,3 +7,5 @@ ROADMAP.md
|
||||
build
|
||||
.env
|
||||
data.db
|
||||
app/node_modules
|
||||
app/build
|
||||
|
@@ -2,8 +2,12 @@ ENV=production
|
||||
DATABASE_URL=data.db
|
||||
DATABASE_TYPE=sqlite
|
||||
ADMIN_SECRET=admin
|
||||
DISABLE_EMAIL_VERIFICATION=true
|
||||
JWT_SECRET=random_string
|
||||
SENDER_EMAIL=info@authorizer.dev
|
||||
SMTP_USERNAME=username
|
||||
SMTP_PASSWORD=password
|
||||
SMTP_HOST=smtp.mailtrap.io
|
||||
SMTP_PORT=2525
|
||||
JWT_TYPE=HS256
|
||||
ROLES=user
|
||||
DEFAULT_ROLES=user
|
||||
|
189
.github/CONTRIBUTING.md
vendored
189
.github/CONTRIBUTING.md
vendored
@@ -49,3 +49,192 @@ Please ask as many questions as you need, either directly in the issue or on [Di
|
||||
5. Build the code `make clean && make`
|
||||
> Note: if you don't have [`make`](https://www.ibm.com/docs/en/aix/7.2?topic=concepts-make-command), you can `cd` into `server` dir and build using the `go build` command
|
||||
6. Run binary `./build/server`
|
||||
|
||||
### Testing
|
||||
|
||||
Make sure you test before creating PR.
|
||||
|
||||
If you want to test for all the databases that authorizer supports you will have to run `mongodb` & `arangodb` instances locally.
|
||||
|
||||
Setup mongodb & arangodb using Docker
|
||||
|
||||
```
|
||||
docker run --name mongodb -d -p 27017:27017 mongo
|
||||
docker run --name arangodb -d -p 8529:8529 -e ARANGO_ROOT_PASSWORD=root arangodb/arangodb:3.8.4
|
||||
```
|
||||
> Note: If you are not making any changes in db schema / db operations, you can disable those db tests [here](https://github.com/authorizerdev/authorizer/blob/main/server/__test__/resolvers_test.go#L14)
|
||||
|
||||
If you are adding new resolver,
|
||||
1. create new resolver test file [here](https://github.com/authorizerdev/authorizer/tree/main/server/__test__)
|
||||
Naming convention filename: `resolver_name_test.go` function name: `resolverNameTest(s TestSetup, t *testing.T)`
|
||||
2. Add your tests [here](https://github.com/authorizerdev/authorizer/blob/main/server/__test__/resolvers_test.go#L38)
|
||||
|
||||
__Command to run tests:__
|
||||
|
||||
```sh
|
||||
make test
|
||||
```
|
||||
|
||||
__Manual Testing:__
|
||||
|
||||
For manually testing using graphql playground, you can paste following queries and mutations in your playground and test it
|
||||
|
||||
```gql
|
||||
mutation Signup {
|
||||
signup(params: {
|
||||
email: "lakhan@yopmail.com",
|
||||
password: "test",
|
||||
confirm_password: "test",
|
||||
given_name: "lakhan"
|
||||
}) {
|
||||
message
|
||||
user {
|
||||
id
|
||||
family_name
|
||||
given_name
|
||||
email
|
||||
email_verified
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutation ResendEamil {
|
||||
resend_verify_email(params: {
|
||||
email: "lakhan@yopmail.com"
|
||||
identifier: "basic_auth_signup"
|
||||
}) {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
query GetVerifyRequests {
|
||||
_verification_requests {
|
||||
id
|
||||
token
|
||||
expires
|
||||
identifier
|
||||
}
|
||||
}
|
||||
|
||||
mutation VerifyEmail {
|
||||
verify_email(params: {
|
||||
token: ""
|
||||
}) {
|
||||
access_token
|
||||
expires_at
|
||||
user {
|
||||
id
|
||||
email
|
||||
given_name
|
||||
email_verified
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutation Login {
|
||||
login(params: {
|
||||
email: "lakhan@yopmail.com",
|
||||
password: "test"
|
||||
}) {
|
||||
access_token
|
||||
expires_at
|
||||
user {
|
||||
id
|
||||
family_name
|
||||
given_name
|
||||
email
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query GetSession {
|
||||
session {
|
||||
access_token
|
||||
expires_at
|
||||
user {
|
||||
id
|
||||
given_name
|
||||
family_name
|
||||
email
|
||||
email_verified
|
||||
signup_methods
|
||||
created_at
|
||||
updated_at
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutation ForgotPassword {
|
||||
forgot_password(params: {
|
||||
email: "lakhan@yopmail.com"
|
||||
}) {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
mutation ResetPassword {
|
||||
reset_password(params: {
|
||||
token: ""
|
||||
password: "test"
|
||||
confirm_password: "test"
|
||||
}) {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
mutation UpdateProfile {
|
||||
update_profile(params: {
|
||||
family_name: "samani"
|
||||
}) {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
query GetUsers {
|
||||
_users {
|
||||
id
|
||||
email
|
||||
email_verified
|
||||
given_name
|
||||
family_name
|
||||
picture
|
||||
signup_methods
|
||||
phone_number
|
||||
}
|
||||
}
|
||||
|
||||
mutation MagicLinkLogin {
|
||||
magic_link_login(params: {
|
||||
email: "test@yopmail.com"
|
||||
}) {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
mutation Logout {
|
||||
logout {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
mutation UpdateUser{
|
||||
_update_user(params: {
|
||||
id: "dafc9400-d603-4ade-997c-83fcd54bbd67",
|
||||
roles: ["user", "admin"]
|
||||
}) {
|
||||
email
|
||||
roles
|
||||
}
|
||||
}
|
||||
|
||||
mutation DeleteUser {
|
||||
_delete_user(params: {
|
||||
email: "signup.test134523@yopmail.com"
|
||||
}) {
|
||||
message
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
22
.github/workflows/release.yaml
vendored
22
.github/workflows/release.yaml
vendored
@@ -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
1
.gitignore
vendored
@@ -2,6 +2,7 @@ server/server
|
||||
server/.env
|
||||
data
|
||||
app/node_modules
|
||||
app/build
|
||||
build
|
||||
.env
|
||||
data.db
|
||||
|
21
Dockerfile
21
Dockerfile
@@ -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" ]
|
||||
|
6
Makefile
6
Makefile
@@ -2,8 +2,10 @@ DEFAULT_VERSION=0.1.0-local
|
||||
VERSION := $(or $(VERSION),$(DEFAULT_VERSION))
|
||||
|
||||
cmd:
|
||||
cd server && go build -ldflags "-w -X main.Version=$(VERSION)" -o '../build/server'
|
||||
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:
|
||||
cd server && go clean --testcache && go test ./...
|
||||
cd server && go clean --testcache && go test -v ./__test__
|
@@ -7,7 +7,7 @@
|
||||
Authorizer
|
||||
</h1>
|
||||
|
||||
**Authorizer** is an open-source authentication and authorization solution for your applications. Bring your database and have complete control over the user information. You can self-host authorizer instances and connect to any SQL database.
|
||||
**Authorizer** is an open-source authentication and authorization solution for your applications. Bring your database and have complete control over the user information. You can self-host authorizer instances and connect to any database (Currently supports [Postgres](https://www.postgresql.org/), [MySQL](https://www.mysql.com/), [SQLite](https://www.sqlite.org/index.html), [SQLServer](https://www.microsoft.com/en-us/sql-server/), [MongoDB](https://mongodb.com/),[ArangoDB](https://www.arangodb.com/)).
|
||||
|
||||
## Table of contents
|
||||
|
||||
@@ -149,6 +149,10 @@ Deploy production ready Authorizer instance using [railway.app](https://github.c
|
||||
> Note: One can always disable the email verification to allow open sign up, which is not recommended for production as anyone can use anyone's email address 😅
|
||||
- For persisting user sessions, you will need Redis URL (not in case of railway.app). If you do not configure a Redis server, sessions will be persisted until the instance is up or not restarted. For better response time on authorization requests/middleware, we recommend deploying Redis on the same infra/network as your authorizer server.
|
||||
|
||||
## Testing
|
||||
|
||||
- Check the testing instructions [here](https://github.com/authorizerdev/authorizer/blob/main/.github/CONTRIBUTING.md#testing)
|
||||
|
||||
## Integrating into your website
|
||||
|
||||
This example demonstrates how you can use [`@authorizerdev/authorizer-js`](/authorizer-js/getting-started) CDN version and have login ready for your site in few seconds. You can also use the ES module version of [`@authorizerdev/authorizer-js`](/authorizer-js/getting-started) or framework-specific versions like [`@authorizerdev/authorizer-react`](/authorizer-react/getting-started)
|
||||
|
10
TODO.md
10
TODO.md
@@ -1,5 +1,15 @@
|
||||
# Task List
|
||||
|
||||
## Open ID compatible claims and schema
|
||||
|
||||
- [x] Rename `schema.graphqls` and re generate schema
|
||||
- [x] Rename to snake case [files + schema]
|
||||
- [x] Refactor db models
|
||||
- [x] Check extra data in oauth profile and save accordingly
|
||||
- [x] Update all the resolver to make them compatible with schema changes
|
||||
- [x] Update JWT claims
|
||||
- [x] Write integration tests for all resolvers
|
||||
|
||||
## Feature Multiple sessions
|
||||
|
||||
- Multiple sessions for users to login use hMset from redis for this
|
||||
|
@@ -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
11
app/esbuild.config.js
Normal 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__,
|
||||
});
|
185
app/package-lock.json
generated
185
app/package-lock.json
generated
@@ -5,111 +5,119 @@
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-js": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.1.0.tgz",
|
||||
"integrity": "sha512-wNtTrFYg4qjvI+Sm58d9E8x+XaiwCA0DCyG87e37YDXmMlvvOmRQf05dxRRxZoxNC1WUkA3UYMTAclCKkonZAg==",
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.2.0.tgz",
|
||||
"integrity": "sha512-T2gurEYEP1T56j9IwDIWP1PsELoWcU7TBl5G0UsMqFQhKo7T6p2hM634Z7PS1yLegU3aihuvHGI0C0n4xSo0VQ==",
|
||||
"requires": {
|
||||
"node-fetch": "^2.6.1"
|
||||
}
|
||||
},
|
||||
"@authorizerdev/authorizer-react": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.1.0.tgz",
|
||||
"integrity": "sha512-+ro0CNKIvblEgRs5M0HevUYrXC6s433GinL7EubIL5XztN48GDBV2GI86lhl4WvjbYTZApZloXWczaZ51g8uig==",
|
||||
"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.1.0",
|
||||
"@authorizerdev/authorizer-js": "^0.2.0",
|
||||
"final-form": "^4.20.2",
|
||||
"react-final-form": "^6.5.3",
|
||||
"styled-components": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"@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.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.0.tgz",
|
||||
"integrity": "sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==",
|
||||
"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.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.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.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.3.tgz",
|
||||
"integrity": "sha512-dcNwU1O4sx57ClvLBVFbEgx0UZWfd0JQX5X6fxFRCLHelFBGXFfSz6Y0FAq2PEwUqlqLkdVjVr4VASEOuUnLJw=="
|
||||
"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",
|
||||
@@ -120,37 +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.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.3.tgz",
|
||||
"integrity": "sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==",
|
||||
"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.0",
|
||||
"@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.3",
|
||||
"@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"
|
||||
}
|
||||
},
|
||||
@@ -241,12 +250,12 @@
|
||||
}
|
||||
},
|
||||
"babel-plugin-styled-components": {
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.13.3.tgz",
|
||||
"integrity": "sha512-meGStRGv+VuKA/q0/jXxrPNWEm4LPfYIqxooDTdmh8kFsP/Ph7jJG5rUPwUPX3QHUvggwdbgdGpo88P/rRYsVw==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.2.tgz",
|
||||
"integrity": "sha512-7eG5NE8rChnNTDxa6LQfynwgHTVOYYaHJbUYSlOhk8QBXIQiMBKq4gyfHBBKPrxUcVBXVJL61ihduCpCQbuNbw==",
|
||||
"requires": {
|
||||
"@babel/helper-annotate-as-pure": "^7.15.4",
|
||||
"@babel/helper-module-imports": "^7.15.4",
|
||||
"@babel/helper-annotate-as-pure": "^7.16.0",
|
||||
"@babel/helper-module-imports": "^7.16.0",
|
||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
||||
"lodash": "^4.17.11"
|
||||
}
|
||||
@@ -305,9 +314,9 @@
|
||||
"integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
@@ -323,9 +332,9 @@
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"final-form": {
|
||||
"version": "4.20.4",
|
||||
"resolved": "https://registry.npmjs.org/final-form/-/final-form-4.20.4.tgz",
|
||||
"integrity": "sha512-hyoOVVilPLpkTvgi+FSJkFZrh0Yhy4BhE6lk/NiBwrF4aRV8/ykKEyXYvQH/pfUbRkOosvpESYouFb+FscsLrw==",
|
||||
"version": "4.20.6",
|
||||
"resolved": "https://registry.npmjs.org/final-form/-/final-form-4.20.6.tgz",
|
||||
"integrity": "sha512-fCdwIj49KOaFfDRlXB57Eo+GghIMZQWrA9TakQI3C9uQxHwaFHXqZSNRlUdfnQmNNeySwGOaGPZCvjy58hyv4w==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.10.0"
|
||||
}
|
||||
@@ -432,9 +441,9 @@
|
||||
}
|
||||
},
|
||||
"postcss-value-parser": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
|
||||
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ=="
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.7.2",
|
||||
@@ -481,9 +490,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz",
|
||||
"integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==",
|
||||
"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"
|
||||
}
|
||||
|
@@ -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.1.0",
|
||||
"@authorizerdev/authorizer-react": "latest",
|
||||
"@types/react": "^17.0.15",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"esbuild": "^0.12.17",
|
||||
|
@@ -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
16
app/src/index.css
Normal 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;
|
||||
}
|
@@ -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'));
|
||||
|
@@ -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"
|
||||
|
27
server/__test__/cors_test.go
Normal file
27
server/__test__/cors_test.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCors(t *testing.T) {
|
||||
allowedOrigin := "http://localhost:8080" // The allowed origin that you want to check
|
||||
notAllowedOrigin := "http://myapp.com"
|
||||
|
||||
s := testSetup()
|
||||
defer s.Server.Close()
|
||||
client := &http.Client{}
|
||||
|
||||
req, _ := createContext(s)
|
||||
req.Header.Add("Origin", allowedOrigin)
|
||||
res, _ := client.Do(req)
|
||||
|
||||
// You should get your origin (or a * depending on your config) if the
|
||||
// passed origin is allowed.
|
||||
o := res.Header.Get("Access-Control-Allow-Origin")
|
||||
assert.NotEqual(t, o, notAllowedOrigin, "Origins should not match")
|
||||
assert.Equal(t, o, allowedOrigin, "Origins do match")
|
||||
}
|
34
server/__test__/delete_user_test.go
Normal file
34
server/__test__/delete_user_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func deleteUserTest(s TestSetup, t *testing.T) {
|
||||
t.Run(`should delete users with admin secret only`, func(t *testing.T) {
|
||||
req, ctx := createContext(s)
|
||||
email := "delete_user." + s.TestInfo.Email
|
||||
resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
_, err := resolvers.DeleteUser(ctx, model.DeleteUserInput{
|
||||
Email: email,
|
||||
})
|
||||
assert.NotNil(t, err, "unauthorized")
|
||||
|
||||
req.Header.Add("x-authorizer-admin-secret", constants.ADMIN_SECRET)
|
||||
_, err = resolvers.DeleteUser(ctx, model.DeleteUserInput{
|
||||
Email: email,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
@@ -1,23 +1,19 @@
|
||||
package env
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEnvs(t *testing.T) {
|
||||
constants.ENV_PATH = "../../.env.sample"
|
||||
InitEnv()
|
||||
|
||||
assert.Equal(t, constants.ADMIN_SECRET, "admin")
|
||||
assert.Equal(t, constants.ENV, "production")
|
||||
assert.Equal(t, constants.DATABASE_URL, "data.db")
|
||||
assert.Equal(t, constants.DATABASE_TYPE, enum.Sqlite.String())
|
||||
assert.True(t, constants.DISABLE_EMAIL_VERIFICATION)
|
||||
assert.True(t, constants.DISABLE_MAGIC_LOGIN)
|
||||
assert.False(t, constants.DISABLE_EMAIL_VERIFICATION)
|
||||
assert.False(t, constants.DISABLE_MAGIC_LINK_LOGIN)
|
||||
assert.False(t, constants.DISABLE_BASIC_AUTHENTICATION)
|
||||
assert.Equal(t, constants.JWT_TYPE, "HS256")
|
||||
assert.Equal(t, constants.JWT_SECRET, "random_string")
|
35
server/__test__/forgot_password_test.go
Normal file
35
server/__test__/forgot_password_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func forgotPasswordTest(s TestSetup, t *testing.T) {
|
||||
t.Run(`should run forgot password`, func(t *testing.T) {
|
||||
_, ctx := createContext(s)
|
||||
email := "forgot_password." + s.TestInfo.Email
|
||||
_, err := resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
_, err = resolvers.ForgotPassword(ctx, model.ForgotPasswordInput{
|
||||
Email: email,
|
||||
})
|
||||
assert.Nil(t, err, "no errors for forgot password")
|
||||
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.ForgotPassword.String())
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, verificationRequest.Identifier, enum.ForgotPassword.String())
|
||||
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
58
server/__test__/login_test.go
Normal file
58
server/__test__/login_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func loginTests(s TestSetup, t *testing.T) {
|
||||
t.Run(`should login`, func(t *testing.T) {
|
||||
_, ctx := createContext(s)
|
||||
email := "login." + s.TestInfo.Email
|
||||
_, err := resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
_, err = resolvers.Login(ctx, model.LoginInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
assert.NotNil(t, err, "should fail because email is not verified")
|
||||
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String())
|
||||
resolvers.VerifyEmail(ctx, model.VerifyEmailInput{
|
||||
Token: verificationRequest.Token,
|
||||
})
|
||||
|
||||
_, err = resolvers.Login(ctx, model.LoginInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
Roles: []string{"test"},
|
||||
})
|
||||
assert.NotNil(t, err, "invalid roles")
|
||||
|
||||
_, err = resolvers.Login(ctx, model.LoginInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password + "s",
|
||||
})
|
||||
assert.NotNil(t, err, "invalid password")
|
||||
|
||||
loginRes, err := resolvers.Login(ctx, model.LoginInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
assert.Nil(t, err, "login successful")
|
||||
assert.NotNil(t, loginRes.AccessToken, "access token should not be empty")
|
||||
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
35
server/__test__/logout_test.go
Normal file
35
server/__test__/logout_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func logoutTests(s TestSetup, t *testing.T) {
|
||||
t.Run(`should logout user`, func(t *testing.T) {
|
||||
req, ctx := createContext(s)
|
||||
email := "logout." + s.TestInfo.Email
|
||||
|
||||
_, err := resolvers.MagicLinkLogin(ctx, model.MagicLinkLoginInput{
|
||||
Email: email,
|
||||
})
|
||||
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.MagicLinkLogin.String())
|
||||
verifyRes, err := resolvers.VerifyEmail(ctx, model.VerifyEmailInput{
|
||||
Token: verificationRequest.Token,
|
||||
})
|
||||
|
||||
token := *verifyRes.AccessToken
|
||||
req.Header.Add("Authorization", "Bearer "+token)
|
||||
_, err = resolvers.Logout(ctx)
|
||||
assert.Nil(t, err)
|
||||
_, err = resolvers.Profile(ctx)
|
||||
assert.NotNil(t, err, "unauthorized")
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
35
server/__test__/magic_link_login_test.go
Normal file
35
server/__test__/magic_link_login_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func magicLinkLoginTests(s TestSetup, t *testing.T) {
|
||||
t.Run(`should login with magic link`, func(t *testing.T) {
|
||||
req, ctx := createContext(s)
|
||||
email := "magic_link_login." + s.TestInfo.Email
|
||||
|
||||
_, err := resolvers.MagicLinkLogin(ctx, model.MagicLinkLoginInput{
|
||||
Email: email,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.MagicLinkLogin.String())
|
||||
verifyRes, err := resolvers.VerifyEmail(ctx, model.VerifyEmailInput{
|
||||
Token: verificationRequest.Token,
|
||||
})
|
||||
|
||||
token := *verifyRes.AccessToken
|
||||
req.Header.Add("Authorization", "Bearer "+token)
|
||||
_, err = resolvers.Profile(ctx)
|
||||
assert.Nil(t, err)
|
||||
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
23
server/__test__/meta_test.go
Normal file
23
server/__test__/meta_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func metaTests(s TestSetup, t *testing.T) {
|
||||
t.Run(`should get meta information`, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
meta, err := resolvers.Meta(ctx)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, meta.IsFacebookLoginEnabled)
|
||||
assert.False(t, meta.IsGoogleLoginEnabled)
|
||||
assert.False(t, meta.IsGithubLoginEnabled)
|
||||
assert.True(t, meta.IsEmailVerificationEnabled)
|
||||
assert.True(t, meta.IsBasicAuthenticationEnabled)
|
||||
assert.True(t, meta.IsMagicLinkLoginEnabled)
|
||||
})
|
||||
}
|
42
server/__test__/profile_test.go
Normal file
42
server/__test__/profile_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func profileTests(s TestSetup, t *testing.T) {
|
||||
t.Run(`should get profile only with token`, func(t *testing.T) {
|
||||
req, ctx := createContext(s)
|
||||
email := "profile." + s.TestInfo.Email
|
||||
|
||||
resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
_, err := resolvers.Profile(ctx)
|
||||
assert.NotNil(t, err, "unauthorized")
|
||||
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String())
|
||||
verifyRes, err := resolvers.VerifyEmail(ctx, model.VerifyEmailInput{
|
||||
Token: verificationRequest.Token,
|
||||
})
|
||||
|
||||
token := *verifyRes.AccessToken
|
||||
req.Header.Add("Authorization", "Bearer "+token)
|
||||
profileRes, err := resolvers.Profile(ctx)
|
||||
assert.Nil(t, err)
|
||||
|
||||
newEmail := *&profileRes.Email
|
||||
assert.Equal(t, email, newEmail, "emails should be equal")
|
||||
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
31
server/__test__/resend_verify_email_test.go
Normal file
31
server/__test__/resend_verify_email_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func resendVerifyEmailTests(s TestSetup, t *testing.T) {
|
||||
t.Run(`should resend verification email`, func(t *testing.T) {
|
||||
_, ctx := createContext(s)
|
||||
email := "resend_verify_email." + s.TestInfo.Email
|
||||
_, err := resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
_, err = resolvers.ResendVerifyEmail(ctx, model.ResendVerifyEmailInput{
|
||||
Email: email,
|
||||
Identifier: enum.BasicAuthSignup.String(),
|
||||
})
|
||||
|
||||
assert.Nil(t, err)
|
||||
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
49
server/__test__/reset_password_test.go
Normal file
49
server/__test__/reset_password_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func resetPasswordTest(s TestSetup, t *testing.T) {
|
||||
t.Run(`should reset password`, func(t *testing.T) {
|
||||
email := "reset_password." + s.TestInfo.Email
|
||||
_, ctx := createContext(s)
|
||||
_, err := resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
_, err = resolvers.ForgotPassword(ctx, model.ForgotPasswordInput{
|
||||
Email: email,
|
||||
})
|
||||
assert.Nil(t, err, "no errors for forgot password")
|
||||
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.ForgotPassword.String())
|
||||
assert.Nil(t, err, "should get forgot password request")
|
||||
|
||||
_, err = resolvers.ResetPassword(ctx, model.ResetPasswordInput{
|
||||
Token: verificationRequest.Token,
|
||||
Password: "test1",
|
||||
ConfirmPassword: "test",
|
||||
})
|
||||
|
||||
assert.NotNil(t, err, "passowrds don't match")
|
||||
|
||||
_, err = resolvers.ResetPassword(ctx, model.ResetPasswordInput{
|
||||
Token: verificationRequest.Token,
|
||||
Password: "test1",
|
||||
ConfirmPassword: "test1",
|
||||
})
|
||||
|
||||
assert.Nil(t, err, "password changed successfully")
|
||||
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
47
server/__test__/resolvers_test.go
Normal file
47
server/__test__/resolvers_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
)
|
||||
|
||||
func TestResolvers(t *testing.T) {
|
||||
databases := map[string]string{
|
||||
enum.Sqlite.String(): "../../data.db",
|
||||
enum.Arangodb.String(): "http://root:root@localhost:8529",
|
||||
enum.Mongodb.String(): "mongodb://localhost:27017",
|
||||
}
|
||||
|
||||
for dbType, dbURL := range databases {
|
||||
constants.DATABASE_URL = dbURL
|
||||
constants.DATABASE_TYPE = dbType
|
||||
db.InitDB()
|
||||
|
||||
s := testSetup()
|
||||
defer s.Server.Close()
|
||||
|
||||
t.Run("should pass tests for "+dbType, func(t *testing.T) {
|
||||
loginTests(s, t)
|
||||
signupTests(s, t)
|
||||
forgotPasswordTest(s, t)
|
||||
resendVerifyEmailTests(s, t)
|
||||
resetPasswordTest(s, t)
|
||||
verifyEmailTest(s, t)
|
||||
sessionTests(s, t)
|
||||
profileTests(s, t)
|
||||
updateProfileTests(s, t)
|
||||
magicLinkLoginTests(s, t)
|
||||
logoutTests(s, t)
|
||||
metaTests(s, t)
|
||||
|
||||
// admin tests
|
||||
verificationRequestsTest(s, t)
|
||||
usersTest(s, t)
|
||||
deleteUserTest(s, t)
|
||||
updateUserTest(s, t)
|
||||
})
|
||||
}
|
||||
}
|
42
server/__test__/session_test.go
Normal file
42
server/__test__/session_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func sessionTests(s TestSetup, t *testing.T) {
|
||||
t.Run(`should allow access to profile with session only`, func(t *testing.T) {
|
||||
req, ctx := createContext(s)
|
||||
email := "session." + s.TestInfo.Email
|
||||
|
||||
resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
_, err := resolvers.Session(ctx, []string{})
|
||||
assert.NotNil(t, err, "unauthorized")
|
||||
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String())
|
||||
verifyRes, err := resolvers.VerifyEmail(ctx, model.VerifyEmailInput{
|
||||
Token: verificationRequest.Token,
|
||||
})
|
||||
|
||||
token := *verifyRes.AccessToken
|
||||
req.Header.Add("Authorization", "Bearer "+token)
|
||||
sessionRes, err := resolvers.Session(ctx, []string{})
|
||||
assert.Nil(t, err)
|
||||
|
||||
newToken := *sessionRes.AccessToken
|
||||
assert.Equal(t, token, newToken, "tokens should be equal")
|
||||
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
47
server/__test__/signup_test.go
Normal file
47
server/__test__/signup_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func signupTests(s TestSetup, t *testing.T) {
|
||||
t.Run(`should complete the signup and check duplicates`, func(t *testing.T) {
|
||||
_, ctx := createContext(s)
|
||||
email := "signup." + s.TestInfo.Email
|
||||
res, err := resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password + "s",
|
||||
})
|
||||
assert.NotNil(t, err, "invalid password errors")
|
||||
|
||||
res, err = resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
user := *res.User
|
||||
assert.Equal(t, email, user.Email)
|
||||
assert.Nil(t, res.AccessToken, "access token should be nil")
|
||||
|
||||
res, err = resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
assert.NotNil(t, err, "should throw duplicate email error")
|
||||
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String())
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, email, verificationRequest.Email)
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
95
server/__test__/test.go
Normal file
95
server/__test__/test.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/env"
|
||||
"github.com/authorizerdev/authorizer/server/handlers"
|
||||
"github.com/authorizerdev/authorizer/server/middlewares"
|
||||
"github.com/authorizerdev/authorizer/server/session"
|
||||
"github.com/gin-contrib/location"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// common user data to share across tests
|
||||
type TestData struct {
|
||||
Email string
|
||||
Password string
|
||||
}
|
||||
|
||||
type TestSetup struct {
|
||||
GinEngine *gin.Engine
|
||||
GinContext *gin.Context
|
||||
Server *httptest.Server
|
||||
TestInfo TestData
|
||||
}
|
||||
|
||||
func cleanData(email string) {
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String())
|
||||
if err == nil {
|
||||
err = db.Mgr.DeleteVerificationRequest(verificationRequest)
|
||||
}
|
||||
|
||||
verificationRequest, err = db.Mgr.GetVerificationByEmail(email, enum.ForgotPassword.String())
|
||||
if err == nil {
|
||||
err = db.Mgr.DeleteVerificationRequest(verificationRequest)
|
||||
}
|
||||
|
||||
verificationRequest, err = db.Mgr.GetVerificationByEmail(email, enum.UpdateEmail.String())
|
||||
if err == nil {
|
||||
err = db.Mgr.DeleteVerificationRequest(verificationRequest)
|
||||
}
|
||||
|
||||
dbUser, err := db.Mgr.GetUserByEmail(email)
|
||||
if err == nil {
|
||||
db.Mgr.DeleteUser(dbUser)
|
||||
db.Mgr.DeleteUserSession(dbUser.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func createContext(s TestSetup) (*http.Request, context.Context) {
|
||||
req, _ := http.NewRequest(
|
||||
"POST",
|
||||
"http://"+s.Server.Listener.Addr().String()+"/graphql",
|
||||
nil,
|
||||
)
|
||||
|
||||
ctx := context.WithValue(req.Context(), "GinContextKey", s.GinContext)
|
||||
s.GinContext.Request = req
|
||||
return req, ctx
|
||||
}
|
||||
|
||||
func testSetup() TestSetup {
|
||||
testData := TestData{
|
||||
Email: fmt.Sprintf("%d_authorizer_tester@yopmail.com", time.Now().Unix()),
|
||||
Password: "test",
|
||||
}
|
||||
|
||||
constants.ENV_PATH = "../../.env.sample"
|
||||
env.InitEnv()
|
||||
session.InitSession()
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, r := gin.CreateTestContext(w)
|
||||
r.Use(location.Default())
|
||||
r.Use(middlewares.GinContextToContextMiddleware())
|
||||
r.Use(middlewares.CORSMiddleware())
|
||||
|
||||
r.POST("/graphql", handlers.GraphqlHandler())
|
||||
|
||||
server := httptest.NewServer(r)
|
||||
|
||||
return TestSetup{
|
||||
GinEngine: r,
|
||||
GinContext: c,
|
||||
Server: server,
|
||||
TestInfo: testData,
|
||||
}
|
||||
}
|
53
server/__test__/update_profile_test.go
Normal file
53
server/__test__/update_profile_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func updateProfileTests(s TestSetup, t *testing.T) {
|
||||
t.Run(`should update the profile with access token only`, func(t *testing.T) {
|
||||
req, ctx := createContext(s)
|
||||
email := "update_profile." + s.TestInfo.Email
|
||||
|
||||
resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
fName := "samani"
|
||||
_, err := resolvers.UpdateProfile(ctx, model.UpdateProfileInput{
|
||||
FamilyName: &fName,
|
||||
})
|
||||
assert.NotNil(t, err, "unauthorized")
|
||||
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String())
|
||||
verifyRes, err := resolvers.VerifyEmail(ctx, model.VerifyEmailInput{
|
||||
Token: verificationRequest.Token,
|
||||
})
|
||||
|
||||
token := *verifyRes.AccessToken
|
||||
req.Header.Add("Authorization", "Bearer "+token)
|
||||
_, err = resolvers.UpdateProfile(ctx, model.UpdateProfileInput{
|
||||
FamilyName: &fName,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
newEmail := "new_" + email
|
||||
_, err = resolvers.UpdateProfile(ctx, model.UpdateProfileInput{
|
||||
Email: &newEmail,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
_, err = resolvers.Profile(ctx)
|
||||
assert.NotNil(t, err, "unauthorized")
|
||||
|
||||
cleanData(newEmail)
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
40
server/__test__/update_user_test.go
Normal file
40
server/__test__/update_user_test.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func updateUserTest(s TestSetup, t *testing.T) {
|
||||
t.Run(`should update the user with admin secret only`, func(t *testing.T) {
|
||||
req, ctx := createContext(s)
|
||||
email := "update_user." + s.TestInfo.Email
|
||||
signupRes, _ := resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
user := *signupRes.User
|
||||
adminRole := "admin"
|
||||
userRole := "user"
|
||||
newRoles := []*string{&adminRole, &userRole}
|
||||
_, err := resolvers.UpdateUser(ctx, model.UpdateUserInput{
|
||||
ID: user.ID,
|
||||
Roles: newRoles,
|
||||
})
|
||||
assert.NotNil(t, err, "unauthorized")
|
||||
|
||||
req.Header.Add("x-authorizer-admin-secret", constants.ADMIN_SECRET)
|
||||
_, err = resolvers.UpdateUser(ctx, model.UpdateUserInput{
|
||||
ID: user.ID,
|
||||
Roles: newRoles,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
27
server/__test__/urls_test.go
Normal file
27
server/__test__/urls_test.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetHostName(t *testing.T) {
|
||||
authorizer_url := "http://test.herokuapp.com:80"
|
||||
|
||||
host, port := utils.GetHostParts(authorizer_url)
|
||||
expectedHost := "test.herokuapp.com"
|
||||
|
||||
assert.Equal(t, host, expectedHost, "hostname should be equal")
|
||||
assert.Equal(t, port, "80", "port should be 80")
|
||||
}
|
||||
|
||||
func TestGetDomainName(t *testing.T) {
|
||||
authorizer_url := "http://test.herokuapp.com"
|
||||
|
||||
got := utils.GetDomainName(authorizer_url)
|
||||
want := "herokuapp.com"
|
||||
|
||||
assert.Equal(t, got, want, "domain name should be equal")
|
||||
}
|
33
server/__test__/users_test.go
Normal file
33
server/__test__/users_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func usersTest(s TestSetup, t *testing.T) {
|
||||
t.Run(`should get users list with admin secret only`, func(t *testing.T) {
|
||||
req, ctx := createContext(s)
|
||||
email := "users." + s.TestInfo.Email
|
||||
resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
users, err := resolvers.Users(ctx)
|
||||
assert.NotNil(t, err, "unauthorized")
|
||||
|
||||
req.Header.Add("x-authorizer-admin-secret", constants.ADMIN_SECRET)
|
||||
users, err = resolvers.Users(ctx)
|
||||
assert.Nil(t, err)
|
||||
rLen := len(users)
|
||||
assert.GreaterOrEqual(t, rLen, 1)
|
||||
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
43
server/__test__/validator_test.go
Normal file
43
server/__test__/validator_test.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIsValidEmail(t *testing.T) {
|
||||
validEmail := "lakhan@gmail.com"
|
||||
invalidEmail1 := "lakhan"
|
||||
invalidEmail2 := "lakhan.me"
|
||||
|
||||
assert.True(t, utils.IsValidEmail(validEmail), "it should be valid email")
|
||||
assert.False(t, utils.IsValidEmail(invalidEmail1), "it should be invalid email")
|
||||
assert.False(t, utils.IsValidEmail(invalidEmail2), "it should be invalid email")
|
||||
}
|
||||
|
||||
func TestIsValidOrigin(t *testing.T) {
|
||||
// don't use portocal(http/https) for ALLOWED_ORIGINS while testing,
|
||||
// as we trim them off while running the main function
|
||||
constants.ALLOWED_ORIGINS = []string{"localhost:8080", "*.google.com", "*.google.in", "*abc.*"}
|
||||
|
||||
assert.False(t, utils.IsValidOrigin("http://myapp.com"), "it should be invalid origin")
|
||||
assert.False(t, utils.IsValidOrigin("http://appgoogle.com"), "it should be invalid origin")
|
||||
assert.True(t, utils.IsValidOrigin("http://app.google.com"), "it should be valid origin")
|
||||
assert.False(t, utils.IsValidOrigin("http://app.google.ind"), "it should be invalid origin")
|
||||
assert.True(t, utils.IsValidOrigin("http://app.google.in"), "it should be valid origin")
|
||||
assert.True(t, utils.IsValidOrigin("http://xyx.abc.com"), "it should be valid origin")
|
||||
assert.True(t, utils.IsValidOrigin("http://xyx.abc.in"), "it should be valid origin")
|
||||
assert.True(t, utils.IsValidOrigin("http://xyxabc.in"), "it should be valid origin")
|
||||
assert.True(t, utils.IsValidOrigin("http://localhost:8080"), "it should be valid origin")
|
||||
}
|
||||
|
||||
func TestIsValidIdentifier(t *testing.T) {
|
||||
assert.False(t, utils.IsValidVerificationIdentifier("test"), "it should be invalid identifier")
|
||||
assert.True(t, utils.IsValidVerificationIdentifier(enum.BasicAuthSignup.String()), "it should be valid identifier")
|
||||
assert.True(t, utils.IsValidVerificationIdentifier(enum.UpdateEmail.String()), "it should be valid identifier")
|
||||
assert.True(t, utils.IsValidVerificationIdentifier(enum.ForgotPassword.String()), "it should be valid identifier")
|
||||
}
|
35
server/__test__/verification_requests_test.go
Normal file
35
server/__test__/verification_requests_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func verificationRequestsTest(s TestSetup, t *testing.T) {
|
||||
t.Run(`should get verification requests with admin secret only`, func(t *testing.T) {
|
||||
req, ctx := createContext(s)
|
||||
|
||||
email := "verification_requests." + s.TestInfo.Email
|
||||
resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
requests, err := resolvers.VerificationRequests(ctx)
|
||||
assert.NotNil(t, err, "unauthorizer")
|
||||
|
||||
req.Header.Add("x-authorizer-admin-secret", constants.ADMIN_SECRET)
|
||||
requests, err = resolvers.VerificationRequests(ctx)
|
||||
|
||||
assert.Nil(t, err)
|
||||
rLen := len(requests)
|
||||
assert.GreaterOrEqual(t, rLen, 1)
|
||||
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
38
server/__test__/verify_email_test.go
Normal file
38
server/__test__/verify_email_test.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func verifyEmailTest(s TestSetup, t *testing.T) {
|
||||
t.Run(`should verify email`, func(t *testing.T) {
|
||||
_, ctx := createContext(s)
|
||||
email := "verify_email." + s.TestInfo.Email
|
||||
res, err := resolvers.Signup(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
user := *res.User
|
||||
assert.Equal(t, email, user.Email)
|
||||
assert.Nil(t, res.AccessToken, "access token should be nil")
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String())
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, email, verificationRequest.Email)
|
||||
|
||||
verifyRes, err := resolvers.VerifyEmail(ctx, model.VerifyEmailInput{
|
||||
Token: verificationRequest.Token,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NotEqual(t, verifyRes.AccessToken, "", "access token should not be empty")
|
||||
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
package constants
|
||||
|
||||
// this constants are configured via env
|
||||
var (
|
||||
ADMIN_SECRET = ""
|
||||
ENV = ""
|
||||
@@ -10,21 +11,23 @@ var (
|
||||
DATABASE_NAME = ""
|
||||
SMTP_HOST = ""
|
||||
SMTP_PORT = ""
|
||||
SMTP_USERNAME = ""
|
||||
SMTP_PASSWORD = ""
|
||||
SENDER_EMAIL = ""
|
||||
SENDER_PASSWORD = ""
|
||||
JWT_TYPE = ""
|
||||
JWT_SECRET = ""
|
||||
ALLOWED_ORIGINS = []string{}
|
||||
AUTHORIZER_URL = ""
|
||||
APP_URL = ""
|
||||
PORT = "8080"
|
||||
PORT = ""
|
||||
REDIS_URL = ""
|
||||
IS_PROD = false
|
||||
COOKIE_NAME = ""
|
||||
RESET_PASSWORD_URL = ""
|
||||
DISABLE_EMAIL_VERIFICATION = false
|
||||
DISABLE_BASIC_AUTHENTICATION = false
|
||||
DISABLE_MAGIC_LOGIN = false
|
||||
DISABLE_MAGIC_LINK_LOGIN = false
|
||||
DISABLE_LOGIN_PAGE = false
|
||||
|
||||
// ROLES
|
||||
ROLES = []string{}
|
||||
|
@@ -23,7 +23,7 @@ func initArangodb() (arangoDriver.Database, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client, err := arangoDriver.NewClient(arangoDriver.ClientConfig{
|
||||
arangoClient, err := arangoDriver.NewClient(arangoDriver.ClientConfig{
|
||||
Connection: conn,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -32,20 +32,16 @@ func initArangodb() (arangoDriver.Database, error) {
|
||||
|
||||
var arangodb driver.Database
|
||||
|
||||
arangodb_exists, err := client.DatabaseExists(nil, constants.DATABASE_NAME)
|
||||
arangodb_exists, err := arangoClient.DatabaseExists(nil, constants.DATABASE_NAME)
|
||||
|
||||
if arangodb_exists {
|
||||
log.Println(constants.DATABASE_NAME + " db exists already")
|
||||
|
||||
arangodb, err = client.Database(nil, constants.DATABASE_NAME)
|
||||
|
||||
arangodb, err = arangoClient.Database(nil, constants.DATABASE_NAME)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
} else {
|
||||
arangodb, err = client.CreateDatabase(nil, constants.DATABASE_NAME, nil)
|
||||
|
||||
arangodb, err = arangoClient.CreateDatabase(nil, constants.DATABASE_NAME, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -61,11 +57,11 @@ func initArangodb() (arangoDriver.Database, error) {
|
||||
}
|
||||
}
|
||||
userCollection, _ := arangodb.Collection(nil, Collections.User)
|
||||
userCollection.EnsureHashIndex(ctx, []string{"id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
userCollection.EnsureHashIndex(ctx, []string{"email"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
Sparse: true,
|
||||
})
|
||||
userCollection.EnsureHashIndex(ctx, []string{"email"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
userCollection.EnsureHashIndex(ctx, []string{"phone_number"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
Sparse: true,
|
||||
})
|
||||
@@ -79,17 +75,13 @@ func initArangodb() (arangoDriver.Database, error) {
|
||||
log.Println("error creating collection("+Collections.VerificationRequest+"):", err)
|
||||
}
|
||||
}
|
||||
|
||||
verificationRequestCollection, _ := arangodb.Collection(nil, Collections.VerificationRequest)
|
||||
verificationRequestCollection.EnsureHashIndex(ctx, []string{"id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
Sparse: true,
|
||||
})
|
||||
verificationRequestCollection.EnsureHashIndex(ctx, []string{"email", "identifier"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
Sparse: true,
|
||||
})
|
||||
verificationRequestCollection.EnsureHashIndex(ctx, []string{"token"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
@@ -104,8 +96,7 @@ func initArangodb() (arangoDriver.Database, error) {
|
||||
}
|
||||
|
||||
sessionCollection, _ := arangodb.Collection(nil, Collections.Session)
|
||||
sessionCollection.EnsureHashIndex(ctx, []string{"id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
sessionCollection.EnsureHashIndex(ctx, []string{"user_id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
arangoDriver "github.com/arangodb/go-driver"
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/driver/sqlite"
|
||||
@@ -25,13 +26,15 @@ type Manager interface {
|
||||
GetVerificationByToken(token string) (VerificationRequest, error)
|
||||
DeleteVerificationRequest(verificationRequest VerificationRequest) error
|
||||
GetVerificationRequests() ([]VerificationRequest, error)
|
||||
GetVerificationByEmail(email string) (VerificationRequest, error)
|
||||
GetVerificationByEmail(email string, identifier string) (VerificationRequest, error)
|
||||
AddSession(session Session) error
|
||||
DeleteUserSession(userId string) error
|
||||
}
|
||||
|
||||
type manager struct {
|
||||
sqlDB *gorm.DB
|
||||
arangodb arangoDriver.Database
|
||||
mongodb *mongo.Database
|
||||
}
|
||||
|
||||
// mainly used by nosql dbs
|
||||
@@ -42,8 +45,9 @@ type CollectionList struct {
|
||||
}
|
||||
|
||||
var (
|
||||
IsSQL bool
|
||||
IsORMSupported bool
|
||||
IsArangoDB bool
|
||||
IsMongoDB bool
|
||||
Mgr Manager
|
||||
Prefix = "authorizer_"
|
||||
Collections = CollectionList{
|
||||
@@ -57,8 +61,9 @@ func InitDB() {
|
||||
var sqlDB *gorm.DB
|
||||
var err error
|
||||
|
||||
IsSQL = constants.DATABASE_TYPE != enum.Arangodb.String()
|
||||
IsORMSupported = constants.DATABASE_TYPE != enum.Arangodb.String() && constants.DATABASE_TYPE != enum.Mongodb.String()
|
||||
IsArangoDB = constants.DATABASE_TYPE == enum.Arangodb.String()
|
||||
IsMongoDB = constants.DATABASE_TYPE == enum.Mongodb.String()
|
||||
|
||||
// sql db orm config
|
||||
ormConfig := &gorm.Config{
|
||||
@@ -85,19 +90,31 @@ func InitDB() {
|
||||
case enum.Arangodb.String():
|
||||
arangodb, err := initArangodb()
|
||||
if err != nil {
|
||||
log.Fatal("error initing arangodb:", err)
|
||||
log.Fatal("error initializing arangodb:", err)
|
||||
}
|
||||
|
||||
Mgr = &manager{
|
||||
sqlDB: nil,
|
||||
arangodb: arangodb,
|
||||
mongodb: nil,
|
||||
}
|
||||
|
||||
break
|
||||
case enum.Mongodb.String():
|
||||
mongodb, err := initMongodb()
|
||||
if err != nil {
|
||||
log.Fatal("error initializing mongodb connection:", err)
|
||||
}
|
||||
|
||||
// common for all sql dbs that are configured via gorm
|
||||
if IsSQL {
|
||||
Mgr = &manager{
|
||||
sqlDB: nil,
|
||||
arangodb: nil,
|
||||
mongodb: mongodb,
|
||||
}
|
||||
}
|
||||
|
||||
// common for all sql dbs that are configured via go-orm
|
||||
if IsORMSupported {
|
||||
if err != nil {
|
||||
log.Fatal("Failed to init sqlDB:", err)
|
||||
} else {
|
||||
@@ -106,6 +123,7 @@ func InitDB() {
|
||||
Mgr = &manager{
|
||||
sqlDB: sqlDB,
|
||||
arangodb: nil,
|
||||
mongodb: nil,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
77
server/db/mongodb.go
Normal file
77
server/db/mongodb.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"go.mongodb.org/mongo-driver/mongo/readpref"
|
||||
)
|
||||
|
||||
func initMongodb() (*mongo.Database, error) {
|
||||
mongodbOptions := options.Client().ApplyURI(constants.DATABASE_URL)
|
||||
maxWait := time.Duration(5 * time.Second)
|
||||
mongodbOptions.ConnectTimeout = &maxWait
|
||||
mongoClient, err := mongo.NewClient(mongodbOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx, _ := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
err = mongoClient.Connect(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = mongoClient.Ping(ctx, readpref.Primary())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mongodb := mongoClient.Database(constants.DATABASE_NAME, options.Database())
|
||||
|
||||
mongodb.CreateCollection(ctx, Collections.User, options.CreateCollection())
|
||||
userCollection := mongodb.Collection(Collections.User, options.Collection())
|
||||
userCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
mongo.IndexModel{
|
||||
Keys: bson.M{"email": 1},
|
||||
Options: options.Index().SetUnique(true).SetSparse(true),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
userCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
mongo.IndexModel{
|
||||
Keys: bson.M{"phone_number": 1},
|
||||
Options: options.Index().SetUnique(true).SetSparse(true).SetPartialFilterExpression(map[string]interface{}{
|
||||
"phone_number": map[string]string{"$type": "string"},
|
||||
}),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
|
||||
mongodb.CreateCollection(ctx, Collections.VerificationRequest, options.CreateCollection())
|
||||
verificationRequestCollection := mongodb.Collection(Collections.VerificationRequest, options.Collection())
|
||||
verificationRequestCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
mongo.IndexModel{
|
||||
Keys: bson.M{"email": 1, "identifier": 1},
|
||||
Options: options.Index().SetUnique(true).SetSparse(true),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
verificationRequestCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
mongo.IndexModel{
|
||||
Keys: bson.M{"token": 1},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
|
||||
mongodb.CreateCollection(ctx, Collections.Session, options.CreateCollection())
|
||||
sessionCollection := mongodb.Collection(Collections.Session, options.Collection())
|
||||
sessionCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
||||
mongo.IndexModel{
|
||||
Keys: bson.M{"user_id": 1},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
}, options.CreateIndexes())
|
||||
|
||||
return mongodb, nil
|
||||
}
|
@@ -1,23 +1,25 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
Key string `json:"_key,omitempty"` // for arangodb
|
||||
ObjectID string `json:"_id,omitempty"` // for arangodb & mongodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"id"`
|
||||
UserID string `gorm:"type:char(36)" json:"user_id"`
|
||||
User User `json:"-"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
IP string `json:"ip"`
|
||||
CreatedAt int64 `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"`
|
||||
UserID string `gorm:"type:char(36),index:" json:"user_id" bson:"user_id"`
|
||||
User User `json:"-" bson:"-"`
|
||||
UserAgent string `json:"user_agent" bson:"user_agent"`
|
||||
IP string `json:"ip" bson:"ip"`
|
||||
CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"`
|
||||
UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"`
|
||||
}
|
||||
|
||||
// AddSession function to save user sessiosn
|
||||
@@ -26,18 +28,8 @@ func (mgr *manager) AddSession(session Session) error {
|
||||
session.ID = uuid.New().String()
|
||||
}
|
||||
|
||||
if session.CreatedAt == 0 {
|
||||
session.CreatedAt = time.Now().Unix()
|
||||
}
|
||||
|
||||
if session.UpdatedAt == 0 {
|
||||
session.CreatedAt = time.Now().Unix()
|
||||
}
|
||||
|
||||
if IsSQL {
|
||||
// copy id as value for fields required for mongodb & arangodb
|
||||
if IsORMSupported {
|
||||
session.Key = session.ID
|
||||
session.ObjectID = session.ID
|
||||
res := mgr.sqlDB.Clauses(
|
||||
clause.OnConflict{
|
||||
DoNothing: true,
|
||||
@@ -49,7 +41,6 @@ func (mgr *manager) AddSession(session Session) error {
|
||||
}
|
||||
|
||||
if IsArangoDB {
|
||||
|
||||
session.CreatedAt = time.Now().Unix()
|
||||
session.UpdatedAt = time.Now().Unix()
|
||||
sessionCollection, _ := mgr.arangodb.Collection(nil, Collections.Session)
|
||||
@@ -60,5 +51,52 @@ func (mgr *manager) AddSession(session Session) error {
|
||||
}
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
session.Key = session.ID
|
||||
session.CreatedAt = time.Now().Unix()
|
||||
session.UpdatedAt = time.Now().Unix()
|
||||
sessionCollection := mgr.mongodb.Collection(Collections.Session, options.Collection())
|
||||
_, err := sessionCollection.InsertOne(nil, session)
|
||||
if err != nil {
|
||||
log.Println(`error saving session`, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mgr *manager) DeleteUserSession(userId string) error {
|
||||
if IsORMSupported {
|
||||
result := mgr.sqlDB.Where("user_id = ?", userId).Delete(&Session{})
|
||||
|
||||
if result.Error != nil {
|
||||
log.Println(`error deleting session:`, result.Error)
|
||||
return result.Error
|
||||
}
|
||||
}
|
||||
|
||||
if IsArangoDB {
|
||||
query := fmt.Sprintf(`FOR d IN %s FILTER d.user_id == @userId REMOVE { _key: d._key } IN %s`, Collections.Session, Collections.Session)
|
||||
bindVars := map[string]interface{}{
|
||||
"userId": userId,
|
||||
}
|
||||
cursor, err := mgr.arangodb.Query(nil, query, bindVars)
|
||||
if err != nil {
|
||||
log.Println("=> error deleting arangodb session:", err)
|
||||
return err
|
||||
}
|
||||
defer cursor.Close()
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
sessionCollection := mgr.mongodb.Collection(Collections.Session, options.Collection())
|
||||
_, err := sessionCollection.DeleteMany(nil, bson.M{"user_id": userId}, options.Delete())
|
||||
if err != nil {
|
||||
log.Println("error deleting session:", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -1,32 +1,39 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
arangoDriver "github.com/arangodb/go-driver"
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/google/uuid"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Key string `json:"_key,omitempty"` // for arangodb
|
||||
ObjectID string `json:"_id,omitempty"` // for arangodb & mongodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"id"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Email string `gorm:"unique" json:"email"`
|
||||
Password string `gorm:"type:text" json:"password"`
|
||||
SignupMethod string `json:"signup_method"`
|
||||
EmailVerifiedAt int64 `json:"email_verified_at"`
|
||||
CreatedAt int64 `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
Image string `gorm:"type:text" json:"image"`
|
||||
Roles string `json:"roles"`
|
||||
Key string `json:"_key,omitempty" bson:"_key"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"`
|
||||
|
||||
Email string `gorm:"unique" json:"email" bson:"email"`
|
||||
EmailVerifiedAt *int64 `json:"email_verified_at" bson:"email_verified_at"`
|
||||
Password *string `gorm:"type:text" json:"password" bson:"password"`
|
||||
SignupMethods string `json:"signup_methods" bson:"signup_methods"`
|
||||
GivenName *string `json:"given_name" bson:"given_name"`
|
||||
FamilyName *string `json:"family_name" bson:"family_name"`
|
||||
MiddleName *string `json:"middle_name" bson:"middle_name"`
|
||||
Nickname *string `json:"nickname" bson:"nickname"`
|
||||
Gender *string `json:"gender" bson:"gender"`
|
||||
Birthdate *string `json:"birthdate" bson:"birthdate"`
|
||||
PhoneNumber *string `gorm:"unique" json:"phone_number" bson:"phone_number"`
|
||||
PhoneNumberVerifiedAt *int64 `json:"phone_number_verified_at" bson:"phone_number_verified_at"`
|
||||
Picture *string `gorm:"type:text" json:"picture" bson:"picture"`
|
||||
Roles string `json:"roles" bson:"roles"`
|
||||
UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"`
|
||||
CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"`
|
||||
}
|
||||
|
||||
// AddUser function to add user even with email conflict
|
||||
@@ -35,10 +42,13 @@ func (mgr *manager) AddUser(user User) (User, error) {
|
||||
user.ID = uuid.New().String()
|
||||
}
|
||||
|
||||
if IsSQL {
|
||||
if user.Roles == "" {
|
||||
user.Roles = constants.DEFAULT_ROLES[0]
|
||||
}
|
||||
|
||||
if IsORMSupported {
|
||||
// copy id as value for fields required for mongodb & arangodb
|
||||
user.Key = user.ID
|
||||
user.ObjectID = user.ID
|
||||
result := mgr.sqlDB.Clauses(
|
||||
clause.OnConflict{
|
||||
UpdateAll: true,
|
||||
@@ -54,16 +64,28 @@ func (mgr *manager) AddUser(user User) (User, error) {
|
||||
if IsArangoDB {
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
ctx := context.Background()
|
||||
userCollection, _ := mgr.arangodb.Collection(nil, Collections.User)
|
||||
meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), user)
|
||||
meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(nil), user)
|
||||
if err != nil {
|
||||
log.Println("error adding user:", err)
|
||||
return user, err
|
||||
}
|
||||
user.Key = meta.Key
|
||||
user.ObjectID = meta.ID.String()
|
||||
user.ID = meta.ID.String()
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
user.Key = user.ID
|
||||
userCollection := mgr.mongodb.Collection(Collections.User, options.Collection())
|
||||
_, err := userCollection.InsertOne(nil, user)
|
||||
if err != nil {
|
||||
log.Println("error adding user:", err)
|
||||
return user, err
|
||||
}
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
@@ -71,7 +93,7 @@ func (mgr *manager) AddUser(user User) (User, error) {
|
||||
func (mgr *manager) UpdateUser(user User) (User, error) {
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
|
||||
if IsSQL {
|
||||
if IsORMSupported {
|
||||
result := mgr.sqlDB.Save(&user)
|
||||
|
||||
if result.Error != nil {
|
||||
@@ -89,8 +111,18 @@ func (mgr *manager) UpdateUser(user User) (User, error) {
|
||||
}
|
||||
|
||||
user.Key = meta.Key
|
||||
user.ObjectID = meta.ID.String()
|
||||
user.ID = meta.ID.String()
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
userCollection := mgr.mongodb.Collection(Collections.User, options.Collection())
|
||||
_, err := userCollection.UpdateOne(nil, bson.M{"_id": bson.M{"$eq": user.ID}}, bson.M{"$set": user}, options.MergeUpdateOptions())
|
||||
if err != nil {
|
||||
log.Println("error updating user:", err)
|
||||
return user, err
|
||||
}
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
@@ -98,7 +130,7 @@ func (mgr *manager) UpdateUser(user User) (User, error) {
|
||||
func (mgr *manager) GetUsers() ([]User, error) {
|
||||
var users []User
|
||||
|
||||
if IsSQL {
|
||||
if IsORMSupported {
|
||||
result := mgr.sqlDB.Find(&users)
|
||||
if result.Error != nil {
|
||||
log.Println("error getting users:", result.Error)
|
||||
@@ -126,20 +158,37 @@ func (mgr *manager) GetUsers() ([]User, error) {
|
||||
}
|
||||
|
||||
if meta.Key != "" {
|
||||
user.Key = meta.Key
|
||||
user.ObjectID = meta.ID.String()
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
userCollection := mgr.mongodb.Collection(Collections.User, options.Collection())
|
||||
cursor, err := userCollection.Find(nil, bson.M{}, options.Find())
|
||||
if err != nil {
|
||||
log.Println("error getting users:", err)
|
||||
return users, err
|
||||
}
|
||||
defer cursor.Close(nil)
|
||||
|
||||
for cursor.Next(nil) {
|
||||
var user User
|
||||
err := cursor.Decode(&user)
|
||||
if err != nil {
|
||||
return users, err
|
||||
}
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (mgr *manager) GetUserByEmail(email string) (User, error) {
|
||||
var user User
|
||||
|
||||
if IsSQL {
|
||||
if IsORMSupported {
|
||||
result := mgr.sqlDB.Where("email = ?", email).First(&user)
|
||||
|
||||
if result.Error != nil {
|
||||
@@ -173,13 +222,21 @@ func (mgr *manager) GetUserByEmail(email string) (User, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
userCollection := mgr.mongodb.Collection(Collections.User, options.Collection())
|
||||
err := userCollection.FindOne(nil, bson.M{"email": email}).Decode(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (mgr *manager) GetUserByID(id string) (User, error) {
|
||||
var user User
|
||||
|
||||
if IsSQL {
|
||||
if IsORMSupported {
|
||||
result := mgr.sqlDB.Where("id = ?", id).First(&user)
|
||||
|
||||
if result.Error != nil {
|
||||
@@ -188,7 +245,7 @@ func (mgr *manager) GetUserByID(id string) (User, error) {
|
||||
}
|
||||
|
||||
if IsArangoDB {
|
||||
query := fmt.Sprintf("FOR d in %s FILTER d.id == @id LIMIT 1 RETURN d", Collections.User)
|
||||
query := fmt.Sprintf("FOR d in %s FILTER d._id == @id LIMIT 1 RETURN d", Collections.User)
|
||||
bindVars := map[string]interface{}{
|
||||
"id": id,
|
||||
}
|
||||
@@ -199,11 +256,6 @@ func (mgr *manager) GetUserByID(id string) (User, error) {
|
||||
}
|
||||
defer cursor.Close()
|
||||
|
||||
count := cursor.Count()
|
||||
if count == 0 {
|
||||
return user, errors.New("user not found")
|
||||
}
|
||||
|
||||
for {
|
||||
if !cursor.HasMore() {
|
||||
if user.Key == "" {
|
||||
@@ -218,11 +270,19 @@ func (mgr *manager) GetUserByID(id string) (User, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
userCollection := mgr.mongodb.Collection(Collections.User, options.Collection())
|
||||
err := userCollection.FindOne(nil, bson.M{"_id": id}).Decode(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (mgr *manager) DeleteUser(user User) error {
|
||||
if IsSQL {
|
||||
if IsORMSupported {
|
||||
result := mgr.sqlDB.Delete(&user)
|
||||
|
||||
if result.Error != nil {
|
||||
@@ -240,5 +300,14 @@ func (mgr *manager) DeleteUser(user User) error {
|
||||
}
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
userCollection := mgr.mongodb.Collection(Collections.User, options.Collection())
|
||||
_, err := userCollection.DeleteOne(nil, bson.M{"_id": user.ID}, options.Delete())
|
||||
if err != nil {
|
||||
log.Println("error deleting user:", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -3,22 +3,24 @@ package db
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
"github.com/google/uuid"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
type VerificationRequest struct {
|
||||
Key string `json:"_key,omitempty"` // for arangodb
|
||||
ObjectID string `json:"_id,omitempty"` // for arangodb & mongodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"id"`
|
||||
Token string `gorm:"type:text" json:"token"`
|
||||
Identifier string `gorm:"uniqueIndex:idx_email_identifier" json:"identifier"`
|
||||
ExpiresAt int64 `json:"expires_at"`
|
||||
CreatedAt int64 `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
Email string `gorm:"uniqueIndex:idx_email_identifier" json:"email"`
|
||||
Key string `json:"_key,omitempty" bson:"_key"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"`
|
||||
Token string `gorm:"type:text" json:"token" bson:"token"`
|
||||
Identifier string `gorm:"uniqueIndex:idx_email_identifier" json:"identifier" bson:"identifier"`
|
||||
ExpiresAt int64 `json:"expires_at" bson:"expires_at"`
|
||||
CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"`
|
||||
UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"`
|
||||
Email string `gorm:"uniqueIndex:idx_email_identifier" json:"email" bson:"email"`
|
||||
}
|
||||
|
||||
// AddVerification function to add verification record
|
||||
@@ -26,10 +28,9 @@ func (mgr *manager) AddVerification(verification VerificationRequest) (Verificat
|
||||
if verification.ID == "" {
|
||||
verification.ID = uuid.New().String()
|
||||
}
|
||||
if IsSQL {
|
||||
if IsORMSupported {
|
||||
// copy id as value for fields required for mongodb & arangodb
|
||||
verification.Key = verification.ID
|
||||
verification.ObjectID = verification.ID
|
||||
result := mgr.sqlDB.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "email"}, {Name: "identifier"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"token", "expires_at"}),
|
||||
@@ -42,14 +43,30 @@ func (mgr *manager) AddVerification(verification VerificationRequest) (Verificat
|
||||
}
|
||||
|
||||
if IsArangoDB {
|
||||
verification.CreatedAt = time.Now().Unix()
|
||||
verification.UpdatedAt = time.Now().Unix()
|
||||
verificationRequestCollection, _ := mgr.arangodb.Collection(nil, Collections.VerificationRequest)
|
||||
meta, err := verificationRequestCollection.CreateDocument(nil, verification)
|
||||
if err != nil {
|
||||
log.Println("error saving verification record:", err)
|
||||
return verification, err
|
||||
}
|
||||
verification.Key = meta.Key
|
||||
verification.ObjectID = meta.ID.String()
|
||||
verification.ID = meta.ID.String()
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
verification.CreatedAt = time.Now().Unix()
|
||||
verification.UpdatedAt = time.Now().Unix()
|
||||
verification.Key = verification.ID
|
||||
verificationRequestCollection := mgr.mongodb.Collection(Collections.VerificationRequest, options.Collection())
|
||||
_, err := verificationRequestCollection.InsertOne(nil, verification)
|
||||
if err != nil {
|
||||
log.Println("error saving verification record:", err)
|
||||
return verification, err
|
||||
}
|
||||
}
|
||||
|
||||
return verification, nil
|
||||
}
|
||||
|
||||
@@ -57,7 +74,7 @@ func (mgr *manager) AddVerification(verification VerificationRequest) (Verificat
|
||||
func (mgr *manager) GetVerificationRequests() ([]VerificationRequest, error) {
|
||||
var verificationRequests []VerificationRequest
|
||||
|
||||
if IsSQL {
|
||||
if IsORMSupported {
|
||||
result := mgr.sqlDB.Find(&verificationRequests)
|
||||
if result.Error != nil {
|
||||
log.Println("error getting verification requests:", result.Error)
|
||||
@@ -85,20 +102,38 @@ func (mgr *manager) GetVerificationRequests() ([]VerificationRequest, error) {
|
||||
}
|
||||
|
||||
if meta.Key != "" {
|
||||
verificationRequest.Key = meta.Key
|
||||
verificationRequest.ObjectID = meta.ID.String()
|
||||
verificationRequests = append(verificationRequests, verificationRequest)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
verificationRequestCollection := mgr.mongodb.Collection(Collections.VerificationRequest, options.Collection())
|
||||
cursor, err := verificationRequestCollection.Find(nil, bson.M{}, options.Find())
|
||||
if err != nil {
|
||||
log.Println("error getting verification requests:", err)
|
||||
return verificationRequests, err
|
||||
}
|
||||
defer cursor.Close(nil)
|
||||
|
||||
for cursor.Next(nil) {
|
||||
var verificationRequest VerificationRequest
|
||||
err := cursor.Decode(&verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequests, err
|
||||
}
|
||||
verificationRequests = append(verificationRequests, verificationRequest)
|
||||
}
|
||||
}
|
||||
|
||||
return verificationRequests, nil
|
||||
}
|
||||
|
||||
func (mgr *manager) GetVerificationByToken(token string) (VerificationRequest, error) {
|
||||
var verification VerificationRequest
|
||||
|
||||
if IsSQL {
|
||||
if IsORMSupported {
|
||||
result := mgr.sqlDB.Where("token = ?", token).First(&verification)
|
||||
|
||||
if result.Error != nil {
|
||||
@@ -133,13 +168,21 @@ func (mgr *manager) GetVerificationByToken(token string) (VerificationRequest, e
|
||||
}
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
verificationRequestCollection := mgr.mongodb.Collection(Collections.VerificationRequest, options.Collection())
|
||||
err := verificationRequestCollection.FindOne(nil, bson.M{"token": token}).Decode(&verification)
|
||||
if err != nil {
|
||||
return verification, err
|
||||
}
|
||||
}
|
||||
|
||||
return verification, nil
|
||||
}
|
||||
|
||||
func (mgr *manager) GetVerificationByEmail(email string) (VerificationRequest, error) {
|
||||
func (mgr *manager) GetVerificationByEmail(email string, identifier string) (VerificationRequest, error) {
|
||||
var verification VerificationRequest
|
||||
if IsSQL {
|
||||
result := mgr.sqlDB.Where("email = ?", email).First(&verification)
|
||||
if IsORMSupported {
|
||||
result := mgr.sqlDB.Where("email = ? AND identifier = ?", email, identifier).First(&verification)
|
||||
|
||||
if result.Error != nil {
|
||||
log.Println(`error getting verification token:`, result.Error)
|
||||
@@ -148,9 +191,10 @@ func (mgr *manager) GetVerificationByEmail(email string) (VerificationRequest, e
|
||||
}
|
||||
|
||||
if IsArangoDB {
|
||||
query := fmt.Sprintf("FOR d in %s FILTER d.email == @email LIMIT 1 RETURN d", Collections.VerificationRequest)
|
||||
query := fmt.Sprintf("FOR d in %s FILTER d.email == @email FILTER d.identifier == @identifier LIMIT 1 RETURN d", Collections.VerificationRequest)
|
||||
bindVars := map[string]interface{}{
|
||||
"email": email,
|
||||
"identifier": identifier,
|
||||
}
|
||||
|
||||
cursor, err := mgr.arangodb.Query(nil, query, bindVars)
|
||||
@@ -173,11 +217,19 @@ func (mgr *manager) GetVerificationByEmail(email string) (VerificationRequest, e
|
||||
}
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
verificationRequestCollection := mgr.mongodb.Collection(Collections.VerificationRequest, options.Collection())
|
||||
err := verificationRequestCollection.FindOne(nil, bson.M{"email": email, "identifier": identifier}).Decode(&verification)
|
||||
if err != nil {
|
||||
return verification, err
|
||||
}
|
||||
}
|
||||
|
||||
return verification, nil
|
||||
}
|
||||
|
||||
func (mgr *manager) DeleteVerificationRequest(verificationRequest VerificationRequest) error {
|
||||
if IsSQL {
|
||||
if IsORMSupported {
|
||||
result := mgr.sqlDB.Delete(&verificationRequest)
|
||||
|
||||
if result.Error != nil {
|
||||
@@ -195,5 +247,14 @@ func (mgr *manager) DeleteVerificationRequest(verificationRequest VerificationRe
|
||||
}
|
||||
}
|
||||
|
||||
if IsMongoDB {
|
||||
verificationRequestCollection := mgr.mongodb.Collection(Collections.VerificationRequest, options.Collection())
|
||||
_, err := verificationRequestCollection.DeleteOne(nil, bson.M{"_id": verificationRequest.ID}, options.Delete())
|
||||
if err != nil {
|
||||
log.Println("error deleting verification request::", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@@ -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 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}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
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)
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ const (
|
||||
Mysql
|
||||
SQLServer
|
||||
Arangodb
|
||||
Mongodb
|
||||
)
|
||||
|
||||
func (d DbType) String() string {
|
||||
@@ -17,5 +18,6 @@ func (d DbType) String() string {
|
||||
"mysql",
|
||||
"sqlserver",
|
||||
"arangodb",
|
||||
"mongodb",
|
||||
}[d]
|
||||
}
|
@@ -4,7 +4,7 @@ type SignupMethod int
|
||||
|
||||
const (
|
||||
BasicAuth SignupMethod = iota
|
||||
MagicLink
|
||||
MagicLinkLogin
|
||||
Google
|
||||
Github
|
||||
Facebook
|
||||
@@ -13,7 +13,7 @@ const (
|
||||
func (d SignupMethod) String() string {
|
||||
return [...]string{
|
||||
"basic_auth",
|
||||
"magic_link",
|
||||
"magic_link_login",
|
||||
"google",
|
||||
"github",
|
||||
"facebook",
|
247
server/env/env.go
vendored
247
server/env/env.go
vendored
@@ -1,7 +1,6 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -13,7 +12,6 @@ import (
|
||||
|
||||
// build variables
|
||||
var (
|
||||
VERSION string
|
||||
ARG_DB_URL *string
|
||||
ARG_DB_TYPE *string
|
||||
ARG_AUTHORIZER_URL *string
|
||||
@@ -25,13 +23,8 @@ func InitEnv() {
|
||||
if constants.ENV_PATH == "" {
|
||||
constants.ENV_PATH = `.env`
|
||||
}
|
||||
ARG_DB_URL = flag.String("database_url", "", "Database connection string")
|
||||
ARG_DB_TYPE = flag.String("database_type", "", "Database type, possible values are postgres,mysql,sqlite")
|
||||
ARG_AUTHORIZER_URL = flag.String("authorizer_url", "", "URL for authorizer instance, eg: https://xyz.herokuapp.com")
|
||||
ARG_ENV_FILE = flag.String("env_file", "", "Env file path")
|
||||
|
||||
flag.Parse()
|
||||
if *ARG_ENV_FILE != "" {
|
||||
if ARG_ENV_FILE != nil && *ARG_ENV_FILE != "" {
|
||||
constants.ENV_PATH = *ARG_ENV_FILE
|
||||
}
|
||||
|
||||
@@ -40,40 +33,15 @@ func InitEnv() {
|
||||
log.Printf("error loading %s file", constants.ENV_PATH)
|
||||
}
|
||||
|
||||
constants.VERSION = VERSION
|
||||
if constants.ADMIN_SECRET == "" {
|
||||
constants.ADMIN_SECRET = os.Getenv("ADMIN_SECRET")
|
||||
constants.ENV = os.Getenv("ENV")
|
||||
constants.DATABASE_TYPE = os.Getenv("DATABASE_TYPE")
|
||||
constants.DATABASE_URL = os.Getenv("DATABASE_URL")
|
||||
constants.DATABASE_NAME = os.Getenv("DATABASE_NAME")
|
||||
constants.SMTP_HOST = os.Getenv("SMTP_HOST")
|
||||
constants.SMTP_PORT = os.Getenv("SMTP_PORT")
|
||||
constants.SENDER_EMAIL = os.Getenv("SENDER_EMAIL")
|
||||
constants.SENDER_PASSWORD = os.Getenv("SENDER_PASSWORD")
|
||||
constants.JWT_SECRET = os.Getenv("JWT_SECRET")
|
||||
constants.JWT_TYPE = os.Getenv("JWT_TYPE")
|
||||
constants.AUTHORIZER_URL = strings.TrimSuffix(os.Getenv("AUTHORIZER_URL"), "/")
|
||||
constants.PORT = os.Getenv("PORT")
|
||||
constants.REDIS_URL = os.Getenv("REDIS_URL")
|
||||
constants.COOKIE_NAME = os.Getenv("COOKIE_NAME")
|
||||
constants.GOOGLE_CLIENT_ID = os.Getenv("GOOGLE_CLIENT_ID")
|
||||
constants.GOOGLE_CLIENT_SECRET = os.Getenv("GOOGLE_CLIENT_SECRET")
|
||||
constants.GITHUB_CLIENT_ID = os.Getenv("GITHUB_CLIENT_ID")
|
||||
constants.GITHUB_CLIENT_SECRET = os.Getenv("GITHUB_CLIENT_SECRET")
|
||||
constants.FACEBOOK_CLIENT_ID = os.Getenv("FACEBOOK_CLIENT_ID")
|
||||
constants.FACEBOOK_CLIENT_SECRET = os.Getenv("FACEBOOK_CLIENT_SECRET")
|
||||
constants.TWITTER_CLIENT_ID = os.Getenv("TWITTER_CLIENT_ID")
|
||||
constants.TWITTER_CLIENT_SECRET = os.Getenv("TWITTER_CLIENT_SECRET")
|
||||
constants.RESET_PASSWORD_URL = strings.TrimPrefix(os.Getenv("RESET_PASSWORD_URL"), "/")
|
||||
constants.DISABLE_BASIC_AUTHENTICATION = os.Getenv("DISABLE_BASIC_AUTHENTICATION") == "true"
|
||||
constants.DISABLE_EMAIL_VERIFICATION = os.Getenv("DISABLE_EMAIL_VERIFICATION") == "true"
|
||||
constants.DISABLE_MAGIC_LOGIN = os.Getenv("DISABLE_MAGIC_LOGIN") == "true"
|
||||
constants.JWT_ROLE_CLAIM = os.Getenv("JWT_ROLE_CLAIM")
|
||||
|
||||
if constants.ADMIN_SECRET == "" {
|
||||
panic("root admin secret is required")
|
||||
}
|
||||
}
|
||||
|
||||
if constants.ENV == "" {
|
||||
constants.ENV = os.Getenv("ENV")
|
||||
if constants.ENV == "" {
|
||||
constants.ENV = "production"
|
||||
}
|
||||
@@ -84,43 +52,164 @@ func InitEnv() {
|
||||
} else {
|
||||
constants.IS_PROD = false
|
||||
}
|
||||
|
||||
allowedOriginsSplit := strings.Split(os.Getenv("ALLOWED_ORIGINS"), ",")
|
||||
allowedOrigins := []string{}
|
||||
for _, val := range allowedOriginsSplit {
|
||||
trimVal := strings.TrimSpace(val)
|
||||
if trimVal != "" {
|
||||
allowedOrigins = append(allowedOrigins, trimVal)
|
||||
}
|
||||
}
|
||||
if len(allowedOrigins) == 0 {
|
||||
allowedOrigins = []string{"*"}
|
||||
}
|
||||
constants.ALLOWED_ORIGINS = allowedOrigins
|
||||
|
||||
if *ARG_AUTHORIZER_URL != "" {
|
||||
constants.AUTHORIZER_URL = *ARG_AUTHORIZER_URL
|
||||
}
|
||||
|
||||
if *ARG_DB_URL != "" {
|
||||
constants.DATABASE_URL = *ARG_DB_URL
|
||||
}
|
||||
|
||||
if *ARG_DB_TYPE != "" {
|
||||
constants.DATABASE_TYPE = *ARG_DB_TYPE
|
||||
}
|
||||
|
||||
if constants.DATABASE_URL == "" {
|
||||
panic("Database url is required")
|
||||
}
|
||||
|
||||
if constants.DATABASE_TYPE == "" {
|
||||
panic("Database type is required")
|
||||
constants.DATABASE_TYPE = os.Getenv("DATABASE_TYPE")
|
||||
log.Println(constants.DATABASE_TYPE)
|
||||
|
||||
if ARG_DB_TYPE != nil && *ARG_DB_TYPE != "" {
|
||||
constants.DATABASE_TYPE = *ARG_DB_TYPE
|
||||
}
|
||||
|
||||
if constants.DATABASE_TYPE == "" {
|
||||
panic("DATABASE_TYPE is required")
|
||||
}
|
||||
}
|
||||
|
||||
if constants.DATABASE_URL == "" {
|
||||
constants.DATABASE_URL = os.Getenv("DATABASE_URL")
|
||||
|
||||
if ARG_DB_URL != nil && *ARG_DB_URL != "" {
|
||||
constants.DATABASE_URL = *ARG_DB_URL
|
||||
}
|
||||
|
||||
if constants.DATABASE_URL == "" {
|
||||
panic("DATABASE_URL is required")
|
||||
}
|
||||
}
|
||||
|
||||
if constants.DATABASE_NAME == "" {
|
||||
constants.DATABASE_NAME = os.Getenv("DATABASE_NAME")
|
||||
if constants.DATABASE_NAME == "" {
|
||||
constants.DATABASE_NAME = "authorizer"
|
||||
}
|
||||
}
|
||||
|
||||
if constants.SMTP_HOST == "" {
|
||||
constants.SMTP_HOST = os.Getenv("SMTP_HOST")
|
||||
}
|
||||
|
||||
if constants.SMTP_PORT == "" {
|
||||
constants.SMTP_PORT = os.Getenv("SMTP_PORT")
|
||||
}
|
||||
|
||||
if constants.SMTP_USERNAME == "" {
|
||||
constants.SMTP_USERNAME = os.Getenv("SMTP_USERNAME")
|
||||
}
|
||||
|
||||
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 == "" {
|
||||
constants.JWT_SECRET = os.Getenv("JWT_SECRET")
|
||||
}
|
||||
|
||||
if constants.JWT_TYPE == "" {
|
||||
constants.JWT_TYPE = os.Getenv("JWT_TYPE")
|
||||
}
|
||||
|
||||
if constants.JWT_ROLE_CLAIM == "" {
|
||||
constants.JWT_ROLE_CLAIM = os.Getenv("JWT_ROLE_CLAIM")
|
||||
|
||||
if constants.JWT_ROLE_CLAIM == "" {
|
||||
constants.JWT_ROLE_CLAIM = "role"
|
||||
}
|
||||
}
|
||||
|
||||
if constants.AUTHORIZER_URL == "" {
|
||||
constants.AUTHORIZER_URL = strings.TrimSuffix(os.Getenv("AUTHORIZER_URL"), "/")
|
||||
|
||||
if ARG_AUTHORIZER_URL != nil && *ARG_AUTHORIZER_URL != "" {
|
||||
constants.AUTHORIZER_URL = *ARG_AUTHORIZER_URL
|
||||
}
|
||||
}
|
||||
|
||||
if constants.PORT == "" {
|
||||
constants.PORT = os.Getenv("PORT")
|
||||
if constants.PORT == "" {
|
||||
constants.PORT = "8080"
|
||||
}
|
||||
}
|
||||
|
||||
if constants.REDIS_URL == "" {
|
||||
constants.REDIS_URL = os.Getenv("REDIS_URL")
|
||||
}
|
||||
|
||||
if constants.COOKIE_NAME == "" {
|
||||
constants.COOKIE_NAME = os.Getenv("COOKIE_NAME")
|
||||
}
|
||||
|
||||
if constants.GOOGLE_CLIENT_ID == "" {
|
||||
constants.GOOGLE_CLIENT_ID = os.Getenv("GOOGLE_CLIENT_ID")
|
||||
}
|
||||
|
||||
if constants.GOOGLE_CLIENT_SECRET == "" {
|
||||
constants.GOOGLE_CLIENT_SECRET = os.Getenv("GOOGLE_CLIENT_SECRET")
|
||||
}
|
||||
|
||||
if constants.GITHUB_CLIENT_ID == "" {
|
||||
constants.GITHUB_CLIENT_ID = os.Getenv("GITHUB_CLIENT_ID")
|
||||
}
|
||||
|
||||
if constants.GITHUB_CLIENT_SECRET == "" {
|
||||
constants.GITHUB_CLIENT_SECRET = os.Getenv("GITHUB_CLIENT_SECRET")
|
||||
}
|
||||
|
||||
if constants.FACEBOOK_CLIENT_ID == "" {
|
||||
constants.FACEBOOK_CLIENT_ID = os.Getenv("FACEBOOK_CLIENT_ID")
|
||||
}
|
||||
|
||||
if constants.FACEBOOK_CLIENT_SECRET == "" {
|
||||
constants.FACEBOOK_CLIENT_SECRET = os.Getenv("FACEBOOK_CLIENT_SECRET")
|
||||
}
|
||||
|
||||
if constants.RESET_PASSWORD_URL == "" {
|
||||
constants.RESET_PASSWORD_URL = strings.TrimPrefix(os.Getenv("RESET_PASSWORD_URL"), "/")
|
||||
}
|
||||
|
||||
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.SMTP_USERNAME == "" || constants.SMTP_PASSWORD == "" || constants.SENDER_EMAIL == "" {
|
||||
constants.DISABLE_EMAIL_VERIFICATION = true
|
||||
constants.DISABLE_MAGIC_LINK_LOGIN = true
|
||||
}
|
||||
|
||||
allowedOriginsSplit := strings.Split(os.Getenv("ALLOWED_ORIGINS"), ",")
|
||||
allowedOrigins := []string{}
|
||||
hasWildCard := false
|
||||
|
||||
for _, val := range allowedOriginsSplit {
|
||||
trimVal := strings.TrimSpace(val)
|
||||
if trimVal != "" {
|
||||
if trimVal != "*" {
|
||||
host, port := utils.GetHostParts(trimVal)
|
||||
allowedOrigins = append(allowedOrigins, host+":"+port)
|
||||
} else {
|
||||
hasWildCard = true
|
||||
allowedOrigins = append(allowedOrigins, trimVal)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(allowedOrigins) > 1 && hasWildCard {
|
||||
allowedOrigins = []string{"*"}
|
||||
}
|
||||
|
||||
if len(allowedOrigins) == 0 {
|
||||
allowedOrigins = []string{"*"}
|
||||
}
|
||||
|
||||
constants.ALLOWED_ORIGINS = allowedOrigins
|
||||
|
||||
if constants.JWT_TYPE == "" {
|
||||
constants.JWT_TYPE = "HS256"
|
||||
@@ -130,32 +219,30 @@ func InitEnv() {
|
||||
constants.COOKIE_NAME = "authorizer"
|
||||
}
|
||||
|
||||
if constants.SMTP_HOST == "" || constants.SENDER_EMAIL == "" || constants.SENDER_PASSWORD == "" {
|
||||
constants.DISABLE_EMAIL_VERIFICATION = true
|
||||
constants.DISABLE_MAGIC_LOGIN = true
|
||||
}
|
||||
|
||||
if constants.DISABLE_EMAIL_VERIFICATION {
|
||||
constants.DISABLE_MAGIC_LOGIN = true
|
||||
constants.DISABLE_MAGIC_LINK_LOGIN = true
|
||||
}
|
||||
|
||||
rolesSplit := strings.Split(os.Getenv("ROLES"), ",")
|
||||
rolesEnv := strings.TrimSpace(os.Getenv("ROLES"))
|
||||
rolesSplit := strings.Split(rolesEnv, ",")
|
||||
roles := []string{}
|
||||
if len(rolesSplit) == 0 {
|
||||
if len(rolesEnv) == 0 {
|
||||
roles = []string{"user"}
|
||||
}
|
||||
|
||||
defaultRoleSplit := strings.Split(os.Getenv("DEFAULT_ROLES"), ",")
|
||||
defaultRolesEnv := strings.TrimSpace(os.Getenv("DEFAULT_ROLES"))
|
||||
defaultRoleSplit := strings.Split(defaultRolesEnv, ",")
|
||||
defaultRoles := []string{}
|
||||
|
||||
if len(defaultRoleSplit) == 0 {
|
||||
if len(defaultRolesEnv) == 0 {
|
||||
defaultRoles = []string{"user"}
|
||||
}
|
||||
|
||||
protectedRolesSplit := strings.Split(os.Getenv("PROTECTED_ROLES"), ",")
|
||||
protectedRolesEnv := strings.TrimSpace(os.Getenv("PROTECTED_ROLES"))
|
||||
protectedRolesSplit := strings.Split(protectedRolesEnv, ",")
|
||||
protectedRoles := []string{}
|
||||
|
||||
if len(protectedRolesSplit) > 0 {
|
||||
if len(protectedRolesEnv) > 0 {
|
||||
for _, val := range protectedRolesSplit {
|
||||
trimVal := strings.TrimSpace(val)
|
||||
protectedRoles = append(protectedRoles, trimVal)
|
||||
@@ -181,10 +268,6 @@ func InitEnv() {
|
||||
constants.DEFAULT_ROLES = defaultRoles
|
||||
constants.PROTECTED_ROLES = protectedRoles
|
||||
|
||||
if constants.JWT_ROLE_CLAIM == "" {
|
||||
constants.JWT_ROLE_CLAIM = "role"
|
||||
}
|
||||
|
||||
if os.Getenv("ORGANIZATION_NAME") != "" {
|
||||
constants.ORGANIZATION_NAME = os.Getenv("ORGANIZATION_NAME")
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ module github.com/authorizerdev/authorizer/server
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/99designs/gqlgen v0.13.0
|
||||
github.com/99designs/gqlgen v0.14.0
|
||||
github.com/arangodb/go-driver v1.2.1
|
||||
github.com/coreos/go-oidc/v3 v3.1.0
|
||||
github.com/gin-contrib/location v0.0.2
|
||||
@@ -20,14 +20,17 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f
|
||||
github.com/stretchr/testify v1.7.0 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/ugorji/go v1.2.6 // indirect
|
||||
github.com/vektah/gqlparser/v2 v2.1.0
|
||||
github.com/vektah/gqlparser/v2 v2.2.0
|
||||
go.mongodb.org/mongo-driver v1.8.1
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
|
||||
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
|
||||
|
@@ -31,15 +31,15 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/99designs/gqlgen v0.13.0 h1:haLTcUp3Vwp80xMVEg5KRNwzfUrgFdRmtBY8fuB8scA=
|
||||
github.com/99designs/gqlgen v0.13.0/go.mod h1:NV130r6f4tpRWuAI+zsrSdooO/eWUv+Gyyoi3rEfXIk=
|
||||
github.com/99designs/gqlgen v0.14.0 h1:Wg8aNYQUjMR/4v+W3xD+7SizOy6lSvVeQ06AobNQAXI=
|
||||
github.com/99designs/gqlgen v0.14.0/go.mod h1:S7z4boV+Nx4VvzMUpVrY/YuHjFX4n7rDyuTqvAkuoRE=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/agnivade/levenshtein v1.0.3 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0=
|
||||
github.com/agnivade/levenshtein v1.0.3/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs=
|
||||
github.com/agnivade/levenshtein v1.1.0 h1:n6qGwyHG61v3ABce1rPVZklEYRT8NFpCMrpZdBUbYGM=
|
||||
github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/arangodb/go-driver v1.2.1 h1:HREDHhDmzdIWxHmfkfTESbYUnRjESjPh4WUuXq7FZa8=
|
||||
@@ -73,8 +73,8 @@ github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL
|
||||
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c h1:TUuUh0Xgj97tLMNtWtNvI9mIV6isjEb9lBMNv+77IGM=
|
||||
github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
|
||||
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
@@ -89,7 +89,6 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA=
|
||||
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@@ -109,10 +108,11 @@ github.com/go-redis/redis/v8 v8.11.0 h1:O1Td0mQ8UFChQ3N9zFQqo6kTU2cJ+/it88gDB+zg
|
||||
github.com/go-redis/redis/v8 v8.11.0/go.mod h1:DLomh7y2e3ggQXQLd1YgmvIfecPJoFl7WU5SOQ/r06M=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
@@ -144,6 +144,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
@@ -153,6 +155,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
@@ -242,7 +245,10 @@ github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMW
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
@@ -281,6 +287,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
@@ -321,7 +328,6 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
@@ -331,6 +337,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
|
||||
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
|
||||
@@ -339,13 +347,23 @@ github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ
|
||||
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
||||
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
|
||||
github.com/vektah/gqlparser/v2 v2.1.0 h1:uiKJ+T5HMGGQM2kRKQ8Pxw8+Zq9qhhZhz/lieYvCMns=
|
||||
github.com/vektah/gqlparser/v2 v2.1.0/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms=
|
||||
github.com/vektah/gqlparser/v2 v2.2.0 h1:bAc3slekAAJW6sZTi07aGq0OrfaCjj4jxARAaC7g2EM=
|
||||
github.com/vektah/gqlparser/v2 v2.2.0/go.mod h1:i3mQIGIrbK2PD1RrCeMTlVbkF2FJ6WkU1KJlJlC+3F4=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
|
||||
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
|
||||
github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
|
||||
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.mongodb.org/mongo-driver v1.8.1 h1:OZE4Wni/SJlrcmSIBRYNzunX5TKxjrTS4jKSnA99oKU=
|
||||
go.mongodb.org/mongo-driver v1.8.1/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
@@ -371,6 +389,7 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
@@ -455,6 +474,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -507,6 +527,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
@@ -525,6 +546,7 @@ golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBn
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
@@ -543,7 +565,6 @@ golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
@@ -559,10 +580,12 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -649,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=
|
||||
@@ -656,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=
|
||||
@@ -693,5 +720,5 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,19 +2,10 @@
|
||||
|
||||
package model
|
||||
|
||||
type AdminUpdateUserInput struct {
|
||||
ID string `json:"id"`
|
||||
Email *string `json:"email"`
|
||||
FirstName *string `json:"firstName"`
|
||||
LastName *string `json:"lastName"`
|
||||
Image *string `json:"image"`
|
||||
Roles []*string `json:"roles"`
|
||||
}
|
||||
|
||||
type AuthResponse struct {
|
||||
Message string `json:"message"`
|
||||
AccessToken *string `json:"accessToken"`
|
||||
AccessTokenExpiresAt *int64 `json:"accessTokenExpiresAt"`
|
||||
AccessToken *string `json:"access_token"`
|
||||
ExpiresAt *int64 `json:"expires_at"`
|
||||
User *User `json:"user"`
|
||||
}
|
||||
|
||||
@@ -37,30 +28,30 @@ type LoginInput struct {
|
||||
Roles []string `json:"roles"`
|
||||
}
|
||||
|
||||
type MagicLoginInput struct {
|
||||
type MagicLinkLoginInput struct {
|
||||
Email string `json:"email"`
|
||||
Roles []string `json:"roles"`
|
||||
}
|
||||
|
||||
type Meta struct {
|
||||
Version string `json:"version"`
|
||||
IsGoogleLoginEnabled bool `json:"isGoogleLoginEnabled"`
|
||||
IsFacebookLoginEnabled bool `json:"isFacebookLoginEnabled"`
|
||||
IsTwitterLoginEnabled bool `json:"isTwitterLoginEnabled"`
|
||||
IsGithubLoginEnabled bool `json:"isGithubLoginEnabled"`
|
||||
IsEmailVerificationEnabled bool `json:"isEmailVerificationEnabled"`
|
||||
IsBasicAuthenticationEnabled bool `json:"isBasicAuthenticationEnabled"`
|
||||
IsMagicLoginEnabled bool `json:"isMagicLoginEnabled"`
|
||||
IsGoogleLoginEnabled bool `json:"is_google_login_enabled"`
|
||||
IsFacebookLoginEnabled bool `json:"is_facebook_login_enabled"`
|
||||
IsGithubLoginEnabled bool `json:"is_github_login_enabled"`
|
||||
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
|
||||
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
|
||||
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
|
||||
}
|
||||
|
||||
type ResendVerifyEmailInput struct {
|
||||
Email string `json:"email"`
|
||||
Identifier string `json:"identifier"`
|
||||
}
|
||||
|
||||
type ResetPasswordInput struct {
|
||||
Token string `json:"token"`
|
||||
Password string `json:"password"`
|
||||
ConfirmPassword string `json:"confirmPassword"`
|
||||
ConfirmPassword string `json:"confirm_password"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
@@ -68,36 +59,67 @@ type Response struct {
|
||||
}
|
||||
|
||||
type SignUpInput struct {
|
||||
FirstName *string `json:"firstName"`
|
||||
LastName *string `json:"lastName"`
|
||||
Email string `json:"email"`
|
||||
GivenName *string `json:"given_name"`
|
||||
FamilyName *string `json:"family_name"`
|
||||
MiddleName *string `json:"middle_name"`
|
||||
Nickname *string `json:"nickname"`
|
||||
Gender *string `json:"gender"`
|
||||
Birthdate *string `json:"birthdate"`
|
||||
PhoneNumber *string `json:"phone_number"`
|
||||
Picture *string `json:"picture"`
|
||||
Password string `json:"password"`
|
||||
ConfirmPassword string `json:"confirmPassword"`
|
||||
Image *string `json:"image"`
|
||||
ConfirmPassword string `json:"confirm_password"`
|
||||
Roles []string `json:"roles"`
|
||||
}
|
||||
|
||||
type UpdateProfileInput struct {
|
||||
OldPassword *string `json:"oldPassword"`
|
||||
NewPassword *string `json:"newPassword"`
|
||||
ConfirmNewPassword *string `json:"confirmNewPassword"`
|
||||
FirstName *string `json:"firstName"`
|
||||
LastName *string `json:"lastName"`
|
||||
Image *string `json:"image"`
|
||||
OldPassword *string `json:"old_password"`
|
||||
NewPassword *string `json:"new_password"`
|
||||
ConfirmNewPassword *string `json:"confirm_new_password"`
|
||||
Email *string `json:"email"`
|
||||
GivenName *string `json:"given_name"`
|
||||
FamilyName *string `json:"family_name"`
|
||||
MiddleName *string `json:"middle_name"`
|
||||
Nickname *string `json:"nickname"`
|
||||
Gender *string `json:"gender"`
|
||||
Birthdate *string `json:"birthdate"`
|
||||
PhoneNumber *string `json:"phone_number"`
|
||||
Picture *string `json:"picture"`
|
||||
}
|
||||
|
||||
type UpdateUserInput struct {
|
||||
ID string `json:"id"`
|
||||
Email *string `json:"email"`
|
||||
GivenName *string `json:"given_name"`
|
||||
FamilyName *string `json:"family_name"`
|
||||
MiddleName *string `json:"middle_name"`
|
||||
Nickname *string `json:"nickname"`
|
||||
Gender *string `json:"gender"`
|
||||
Birthdate *string `json:"birthdate"`
|
||||
PhoneNumber *string `json:"phone_number"`
|
||||
Picture *string `json:"picture"`
|
||||
Roles []*string `json:"roles"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
SignupMethod string `json:"signupMethod"`
|
||||
FirstName *string `json:"firstName"`
|
||||
LastName *string `json:"lastName"`
|
||||
EmailVerifiedAt *int64 `json:"emailVerifiedAt"`
|
||||
Image *string `json:"image"`
|
||||
CreatedAt *int64 `json:"createdAt"`
|
||||
UpdatedAt *int64 `json:"updatedAt"`
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
SignupMethods string `json:"signup_methods"`
|
||||
GivenName *string `json:"given_name"`
|
||||
FamilyName *string `json:"family_name"`
|
||||
MiddleName *string `json:"middle_name"`
|
||||
Nickname *string `json:"nickname"`
|
||||
PreferredUsername *string `json:"preferred_username"`
|
||||
Gender *string `json:"gender"`
|
||||
Birthdate *string `json:"birthdate"`
|
||||
PhoneNumber *string `json:"phone_number"`
|
||||
PhoneNumberVerified *bool `json:"phone_number_verified"`
|
||||
Picture *string `json:"picture"`
|
||||
Roles []string `json:"roles"`
|
||||
CreatedAt *int64 `json:"created_at"`
|
||||
UpdatedAt *int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
type VerificationRequest struct {
|
||||
@@ -106,8 +128,8 @@ type VerificationRequest struct {
|
||||
Token *string `json:"token"`
|
||||
Email *string `json:"email"`
|
||||
Expires *int64 `json:"expires"`
|
||||
CreatedAt *int64 `json:"createdAt"`
|
||||
UpdatedAt *int64 `json:"updatedAt"`
|
||||
CreatedAt *int64 `json:"created_at"`
|
||||
UpdatedAt *int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
type VerifyEmailInput struct {
|
||||
|
@@ -7,26 +7,33 @@ scalar Any
|
||||
|
||||
type Meta {
|
||||
version: String!
|
||||
isGoogleLoginEnabled: Boolean!
|
||||
isFacebookLoginEnabled: Boolean!
|
||||
isTwitterLoginEnabled: Boolean!
|
||||
isGithubLoginEnabled: Boolean!
|
||||
isEmailVerificationEnabled: Boolean!
|
||||
isBasicAuthenticationEnabled: Boolean!
|
||||
isMagicLoginEnabled: Boolean!
|
||||
is_google_login_enabled: Boolean!
|
||||
is_facebook_login_enabled: Boolean!
|
||||
is_github_login_enabled: Boolean!
|
||||
is_email_verification_enabled: Boolean!
|
||||
is_basic_authentication_enabled: Boolean!
|
||||
is_magic_link_login_enabled: Boolean!
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
email: String!
|
||||
signupMethod: String!
|
||||
firstName: String
|
||||
lastName: String
|
||||
emailVerifiedAt: Int64
|
||||
image: String
|
||||
createdAt: Int64
|
||||
updatedAt: Int64
|
||||
email_verified: Boolean!
|
||||
signup_methods: String!
|
||||
given_name: String
|
||||
family_name: String
|
||||
middle_name: String
|
||||
nickname: String
|
||||
# defaults to email
|
||||
preferred_username: String
|
||||
gender: String
|
||||
birthdate: String
|
||||
phone_number: String
|
||||
phone_number_verified: Boolean
|
||||
picture: String
|
||||
roles: [String!]!
|
||||
created_at: Int64
|
||||
updated_at: Int64
|
||||
}
|
||||
|
||||
type VerificationRequest {
|
||||
@@ -35,8 +42,8 @@ type VerificationRequest {
|
||||
token: String
|
||||
email: String
|
||||
expires: Int64
|
||||
createdAt: Int64
|
||||
updatedAt: Int64
|
||||
created_at: Int64
|
||||
updated_at: Int64
|
||||
}
|
||||
|
||||
type Error {
|
||||
@@ -46,8 +53,8 @@ type Error {
|
||||
|
||||
type AuthResponse {
|
||||
message: String!
|
||||
accessToken: String
|
||||
accessTokenExpiresAt: Int64
|
||||
access_token: String
|
||||
expires_at: Int64
|
||||
user: User
|
||||
}
|
||||
|
||||
@@ -56,12 +63,17 @@ type Response {
|
||||
}
|
||||
|
||||
input SignUpInput {
|
||||
firstName: String
|
||||
lastName: String
|
||||
email: String!
|
||||
given_name: String
|
||||
family_name: String
|
||||
middle_name: String
|
||||
nickname: String
|
||||
gender: String
|
||||
birthdate: String
|
||||
phone_number: String
|
||||
picture: String
|
||||
password: String!
|
||||
confirmPassword: String!
|
||||
image: String
|
||||
confirm_password: String!
|
||||
roles: [String!]
|
||||
}
|
||||
|
||||
@@ -77,25 +89,35 @@ input VerifyEmailInput {
|
||||
|
||||
input ResendVerifyEmailInput {
|
||||
email: String!
|
||||
identifier: String!
|
||||
}
|
||||
|
||||
input UpdateProfileInput {
|
||||
oldPassword: String
|
||||
newPassword: String
|
||||
confirmNewPassword: String
|
||||
firstName: String
|
||||
lastName: String
|
||||
image: String
|
||||
old_password: String
|
||||
new_password: String
|
||||
confirm_new_password: String
|
||||
email: String
|
||||
# roles: [String]
|
||||
given_name: String
|
||||
family_name: String
|
||||
middle_name: String
|
||||
nickname: String
|
||||
gender: String
|
||||
birthdate: String
|
||||
phone_number: String
|
||||
picture: String
|
||||
}
|
||||
|
||||
input AdminUpdateUserInput {
|
||||
input UpdateUserInput {
|
||||
id: ID!
|
||||
email: String
|
||||
firstName: String
|
||||
lastName: String
|
||||
image: String
|
||||
given_name: String
|
||||
family_name: String
|
||||
middle_name: String
|
||||
nickname: String
|
||||
gender: String
|
||||
birthdate: String
|
||||
phone_number: String
|
||||
picture: String
|
||||
roles: [String]
|
||||
}
|
||||
|
||||
@@ -106,14 +128,14 @@ input ForgotPasswordInput {
|
||||
input ResetPasswordInput {
|
||||
token: String!
|
||||
password: String!
|
||||
confirmPassword: String!
|
||||
confirm_password: String!
|
||||
}
|
||||
|
||||
input DeleteUserInput {
|
||||
email: String!
|
||||
}
|
||||
|
||||
input MagicLoginInput {
|
||||
input MagicLinkLoginInput {
|
||||
email: String!
|
||||
roles: [String!]
|
||||
}
|
||||
@@ -121,21 +143,23 @@ input MagicLoginInput {
|
||||
type Mutation {
|
||||
signup(params: SignUpInput!): AuthResponse!
|
||||
login(params: LoginInput!): AuthResponse!
|
||||
magicLogin(params: MagicLoginInput!): Response!
|
||||
magic_link_login(params: MagicLinkLoginInput!): Response!
|
||||
logout: Response!
|
||||
updateProfile(params: UpdateProfileInput!): Response!
|
||||
adminUpdateUser(params: AdminUpdateUserInput!): User!
|
||||
verifyEmail(params: VerifyEmailInput!): AuthResponse!
|
||||
resendVerifyEmail(params: ResendVerifyEmailInput!): Response!
|
||||
forgotPassword(params: ForgotPasswordInput!): Response!
|
||||
resetPassword(params: ResetPasswordInput!): Response!
|
||||
deleteUser(params: DeleteUserInput!): Response!
|
||||
update_profile(params: UpdateProfileInput!): Response!
|
||||
verify_email(params: VerifyEmailInput!): AuthResponse!
|
||||
resend_verify_email(params: ResendVerifyEmailInput!): Response!
|
||||
forgot_password(params: ForgotPasswordInput!): Response!
|
||||
reset_password(params: ResetPasswordInput!): Response!
|
||||
# admin only apis
|
||||
_delete_user(params: DeleteUserInput!): Response!
|
||||
_update_user(params: UpdateUserInput!): User!
|
||||
}
|
||||
|
||||
type Query {
|
||||
meta: Meta!
|
||||
users: [User!]!
|
||||
token(roles: [String!]): AuthResponse
|
||||
session(roles: [String!]): AuthResponse
|
||||
profile: User!
|
||||
verificationRequests: [VerificationRequest!]!
|
||||
# admin only apis
|
||||
_users: [User!]!
|
||||
_verification_requests: [VerificationRequest!]!
|
||||
}
|
||||
|
@@ -19,8 +19,8 @@ func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (
|
||||
return resolvers.Login(ctx, params)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) MagicLogin(ctx context.Context, params model.MagicLoginInput) (*model.Response, error) {
|
||||
return resolvers.MagicLogin(ctx, params)
|
||||
func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
|
||||
return resolvers.MagicLinkLogin(ctx, params)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) Logout(ctx context.Context) (*model.Response, error) {
|
||||
@@ -31,10 +31,6 @@ func (r *mutationResolver) UpdateProfile(ctx context.Context, params model.Updat
|
||||
return resolvers.UpdateProfile(ctx, params)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) AdminUpdateUser(ctx context.Context, params model.AdminUpdateUserInput) (*model.User, error) {
|
||||
return resolvers.AdminUpdateUser(ctx, params)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.AuthResponse, error) {
|
||||
return resolvers.VerifyEmail(ctx, params)
|
||||
}
|
||||
@@ -55,22 +51,26 @@ func (r *mutationResolver) DeleteUser(ctx context.Context, params model.DeleteUs
|
||||
return resolvers.DeleteUser(ctx, params)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error) {
|
||||
return resolvers.UpdateUser(ctx, params)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Meta(ctx context.Context) (*model.Meta, error) {
|
||||
return resolvers.Meta(ctx)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) {
|
||||
return resolvers.Users(ctx)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Token(ctx context.Context, roles []string) (*model.AuthResponse, error) {
|
||||
return resolvers.Token(ctx, roles)
|
||||
func (r *queryResolver) Session(ctx context.Context, roles []string) (*model.AuthResponse, error) {
|
||||
return resolvers.Session(ctx, roles)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Profile(ctx context.Context) (*model.User, error) {
|
||||
return resolvers.Profile(ctx)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) {
|
||||
return resolvers.Users(ctx)
|
||||
}
|
||||
|
||||
func (r *queryResolver) VerificationRequests(ctx context.Context) ([]*model.VerificationRequest, error) {
|
||||
return resolvers.VerificationRequests(ctx)
|
||||
}
|
||||
@@ -81,5 +81,7 @@ func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResol
|
||||
// Query returns generated.QueryResolver implementation.
|
||||
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
|
||||
|
||||
type mutationResolver struct{ *Resolver }
|
||||
type queryResolver struct{ *Resolver }
|
||||
type (
|
||||
mutationResolver struct{ *Resolver }
|
||||
queryResolver struct{ *Resolver }
|
||||
)
|
||||
|
@@ -49,7 +49,7 @@ func AppHandler() gin.HandlerFunc {
|
||||
stateObj.RedirectURL = strings.TrimSuffix(stateObj.RedirectURL, "/")
|
||||
|
||||
// validate redirect url with allowed origins
|
||||
if !utils.IsValidRedirectURL(stateObj.RedirectURL) {
|
||||
if !utils.IsValidOrigin(stateObj.RedirectURL) {
|
||||
c.JSON(400, gin.H{"error": "invalid redirect url"})
|
||||
return
|
||||
}
|
||||
|
@@ -43,26 +43,10 @@ func processGoogleUserInfo(code string) (db.User, error) {
|
||||
return user, fmt.Errorf("unable to verify id_token: %s", err.Error())
|
||||
}
|
||||
|
||||
// Extract custom claims
|
||||
var claims struct {
|
||||
Email string `json:"email"`
|
||||
Picture string `json:"picture"`
|
||||
GivenName string `json:"given_name"`
|
||||
FamilyName string `json:"family_name"`
|
||||
Verified bool `json:"email_verified"`
|
||||
}
|
||||
if err := idToken.Claims(&claims); err != nil {
|
||||
if err := idToken.Claims(&user); err != nil {
|
||||
return user, fmt.Errorf("unable to extract claims")
|
||||
}
|
||||
|
||||
user = db.User{
|
||||
FirstName: claims.GivenName,
|
||||
LastName: claims.FamilyName,
|
||||
Image: claims.Picture,
|
||||
Email: claims.Email,
|
||||
EmailVerifiedAt: time.Now().Unix(),
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
@@ -104,12 +88,14 @@ func processGithubUserInfo(code string) (db.User, error) {
|
||||
if len(name) > 1 && strings.TrimSpace(name[1]) != "" {
|
||||
lastName = name[0]
|
||||
}
|
||||
|
||||
picture := userRawData["avatar_url"]
|
||||
|
||||
user = db.User{
|
||||
FirstName: firstName,
|
||||
LastName: lastName,
|
||||
Image: userRawData["avatar_url"],
|
||||
GivenName: &firstName,
|
||||
FamilyName: &lastName,
|
||||
Picture: &picture,
|
||||
Email: userRawData["email"],
|
||||
EmailVerifiedAt: time.Now().Unix(),
|
||||
}
|
||||
|
||||
return user, nil
|
||||
@@ -146,12 +132,15 @@ func processFacebookUserInfo(code string) (db.User, error) {
|
||||
|
||||
picObject := userRawData["picture"].(map[string]interface{})["data"]
|
||||
picDataObject := picObject.(map[string]interface{})
|
||||
firstName := fmt.Sprintf("%v", userRawData["first_name"])
|
||||
lastName := fmt.Sprintf("%v", userRawData["last_name"])
|
||||
picture := fmt.Sprintf("%v", picDataObject["url"])
|
||||
|
||||
user = db.User{
|
||||
FirstName: fmt.Sprintf("%v", userRawData["first_name"]),
|
||||
LastName: fmt.Sprintf("%v", userRawData["last_name"]),
|
||||
Image: fmt.Sprintf("%v", picDataObject["url"]),
|
||||
GivenName: &firstName,
|
||||
FamilyName: &lastName,
|
||||
Picture: &picture,
|
||||
Email: email,
|
||||
EmailVerifiedAt: time.Now().Unix(),
|
||||
}
|
||||
|
||||
return user, nil
|
||||
@@ -202,7 +191,7 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||
|
||||
if err != nil {
|
||||
// user not registered, register user and generate session token
|
||||
user.SignupMethod = provider
|
||||
user.SignupMethods = provider
|
||||
// make sure inputRoles don't include protected roles
|
||||
hasProtectedRole := false
|
||||
for _, ir := range inputRoles {
|
||||
@@ -217,16 +206,18 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||
}
|
||||
|
||||
user.Roles = strings.Join(inputRoles, ",")
|
||||
now := time.Now().Unix()
|
||||
user.EmailVerifiedAt = &now
|
||||
user, _ = db.Mgr.AddUser(user)
|
||||
} else {
|
||||
// user exists in db, check if method was google
|
||||
// if not append google to existing signup method and save it
|
||||
|
||||
signupMethod := existingUser.SignupMethod
|
||||
signupMethod := existingUser.SignupMethods
|
||||
if !strings.Contains(signupMethod, provider) {
|
||||
signupMethod = signupMethod + "," + provider
|
||||
}
|
||||
user.SignupMethod = signupMethod
|
||||
user.SignupMethods = signupMethod
|
||||
user.Password = existingUser.Password
|
||||
|
||||
// There multiple scenarios with roles here in social login
|
||||
@@ -262,7 +253,6 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||
user.Roles = existingUser.Roles
|
||||
}
|
||||
user.Key = existingUser.Key
|
||||
user.ObjectID = existingUser.ObjectID
|
||||
user.ID = existingUser.ID
|
||||
user, err = db.Mgr.UpdateUser(user)
|
||||
}
|
||||
@@ -274,15 +264,7 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||
accessToken, _, _ := utils.CreateAuthToken(user, enum.AccessToken, inputRoles)
|
||||
utils.SetCookie(c, accessToken)
|
||||
session.SetToken(userIdStr, accessToken, refreshToken)
|
||||
go func() {
|
||||
sessionData := db.Session{
|
||||
UserID: user.ID,
|
||||
UserAgent: utils.GetUserAgent(c.Request),
|
||||
IP: utils.GetIP(c.Request),
|
||||
}
|
||||
|
||||
db.Mgr.AddSession(sessionData)
|
||||
}()
|
||||
utils.CreateSession(user.ID, c)
|
||||
|
||||
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -46,29 +45,21 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
||||
}
|
||||
|
||||
// update email_verified_at in users table
|
||||
if user.EmailVerifiedAt <= 0 {
|
||||
user.EmailVerifiedAt = time.Now().Unix()
|
||||
if user.EmailVerifiedAt == nil {
|
||||
now := time.Now().Unix()
|
||||
user.EmailVerifiedAt = &now
|
||||
db.Mgr.UpdateUser(user)
|
||||
}
|
||||
// delete from verification table
|
||||
db.Mgr.DeleteVerificationRequest(verificationRequest)
|
||||
|
||||
userIdStr := fmt.Sprintf("%v", user.ID)
|
||||
roles := strings.Split(user.Roles, ",")
|
||||
refreshToken, _, _ := utils.CreateAuthToken(user, enum.RefreshToken, roles)
|
||||
|
||||
accessToken, _, _ := utils.CreateAuthToken(user, enum.AccessToken, roles)
|
||||
|
||||
session.SetToken(userIdStr, accessToken, refreshToken)
|
||||
go func() {
|
||||
sessionData := db.Session{
|
||||
UserID: user.ID,
|
||||
UserAgent: utils.GetUserAgent(c.Request),
|
||||
IP: utils.GetIP(c.Request),
|
||||
}
|
||||
|
||||
db.Mgr.AddSession(sessionData)
|
||||
}()
|
||||
session.SetToken(user.ID, accessToken, refreshToken)
|
||||
utils.CreateSession(user.ID, c)
|
||||
utils.SetCookie(c, accessToken)
|
||||
c.Redirect(http.StatusTemporaryRedirect, claim.RedirectURL)
|
||||
}
|
@@ -1,80 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"flag"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/env"
|
||||
"github.com/authorizerdev/authorizer/server/handlers"
|
||||
"github.com/authorizerdev/authorizer/server/oauth"
|
||||
"github.com/authorizerdev/authorizer/server/router"
|
||||
"github.com/authorizerdev/authorizer/server/session"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
"github.com/gin-contrib/location"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func GinContextToContextMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if constants.AUTHORIZER_URL == "" {
|
||||
url := location.Get(c)
|
||||
constants.AUTHORIZER_URL = url.Scheme + "://" + c.Request.Host
|
||||
log.Println("=> authorizer url:", constants.AUTHORIZER_URL)
|
||||
}
|
||||
ctx := context.WithValue(c.Request.Context(), "GinContextKey", c)
|
||||
c.Request = c.Request.WithContext(ctx)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO use allowed origins for cors origin
|
||||
// TODO throw error if url is not allowed
|
||||
func CORSMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
origin := c.Request.Header.Get("Origin")
|
||||
constants.APP_URL = origin
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
|
||||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
|
||||
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
c.AbortWithStatus(204)
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
var VERSION string
|
||||
|
||||
func main() {
|
||||
env.ARG_DB_URL = flag.String("database_url", "", "Database connection string")
|
||||
env.ARG_DB_TYPE = flag.String("database_type", "", "Database type, possible values are postgres,mysql,sqlite")
|
||||
env.ARG_AUTHORIZER_URL = flag.String("authorizer_url", "", "URL for authorizer instance, eg: https://xyz.herokuapp.com")
|
||||
env.ARG_ENV_FILE = flag.String("env_file", "", "Env file path")
|
||||
flag.Parse()
|
||||
|
||||
constants.VERSION = VERSION
|
||||
|
||||
env.InitEnv()
|
||||
db.InitDB()
|
||||
session.InitSession()
|
||||
oauth.InitOAuth()
|
||||
utils.InitServer()
|
||||
|
||||
r := gin.Default()
|
||||
r.Use(location.Default())
|
||||
r.Use(GinContextToContextMiddleware())
|
||||
r.Use(CORSMiddleware())
|
||||
router := router.InitRouter()
|
||||
|
||||
r.GET("/", handlers.PlaygroundHandler())
|
||||
r.POST("/graphql", handlers.GraphqlHandler())
|
||||
r.GET("/verify_email", handlers.VerifyEmailHandler())
|
||||
r.GET("/oauth_login/:oauth_provider", handlers.OAuthLoginHandler())
|
||||
r.GET("/oauth_callback/:oauth_provider", handlers.OAuthCallbackHandler())
|
||||
|
||||
// login wall app related routes
|
||||
|
||||
r.LoadHTMLGlob("templates/*")
|
||||
app := r.Group("/app")
|
||||
// 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")
|
||||
{
|
||||
app.Static("/build", "app/build")
|
||||
app.GET("/", handlers.AppHandler())
|
||||
app.GET("/reset-password", handlers.AppHandler())
|
||||
}
|
||||
|
||||
r.Run()
|
||||
}
|
||||
|
||||
router.Run(":" + constants.PORT)
|
||||
}
|
||||
|
23
server/middlewares/context.go
Normal file
23
server/middlewares/context.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/gin-contrib/location"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func GinContextToContextMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if constants.AUTHORIZER_URL == "" {
|
||||
url := location.Get(c)
|
||||
constants.AUTHORIZER_URL = url.Scheme + "://" + c.Request.Host
|
||||
log.Println("authorizer url:", constants.AUTHORIZER_URL)
|
||||
}
|
||||
ctx := context.WithValue(c.Request.Context(), "GinContextKey", c)
|
||||
c.Request = c.Request.WithContext(ctx)
|
||||
c.Next()
|
||||
}
|
||||
}
|
29
server/middlewares/cors.go
Normal file
29
server/middlewares/cors.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func CORSMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
origin := c.Request.Header.Get("Origin")
|
||||
constants.APP_URL = origin
|
||||
|
||||
if utils.IsValidOrigin(origin) {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
|
||||
}
|
||||
|
||||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
|
||||
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
c.AbortWithStatus(204)
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
@@ -32,15 +32,15 @@ func Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, e
|
||||
return res, fmt.Errorf(`user with this email not found`)
|
||||
}
|
||||
|
||||
if !strings.Contains(user.SignupMethod, enum.BasicAuth.String()) {
|
||||
if !strings.Contains(user.SignupMethods, enum.BasicAuth.String()) {
|
||||
return res, fmt.Errorf(`user has not signed up email & password`)
|
||||
}
|
||||
|
||||
if user.EmailVerifiedAt <= 0 {
|
||||
if user.EmailVerifiedAt == nil {
|
||||
return res, fmt.Errorf(`email not verified`)
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(params.Password))
|
||||
err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(params.Password))
|
||||
|
||||
if err != nil {
|
||||
log.Println("compare password error:", err)
|
||||
@@ -55,38 +55,18 @@ func Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, e
|
||||
|
||||
roles = params.Roles
|
||||
}
|
||||
userIdStr := fmt.Sprintf("%v", user.ID)
|
||||
refreshToken, _, _ := utils.CreateAuthToken(user, enum.RefreshToken, roles)
|
||||
|
||||
accessToken, expiresAt, _ := utils.CreateAuthToken(user, enum.AccessToken, roles)
|
||||
|
||||
session.SetToken(userIdStr, accessToken, refreshToken)
|
||||
go func() {
|
||||
sessionData := db.Session{
|
||||
UserID: user.ID,
|
||||
UserAgent: utils.GetUserAgent(gc.Request),
|
||||
IP: utils.GetIP(gc.Request),
|
||||
}
|
||||
|
||||
db.Mgr.AddSession(sessionData)
|
||||
}()
|
||||
session.SetToken(user.ID, accessToken, refreshToken)
|
||||
utils.CreateSession(user.ID, gc)
|
||||
|
||||
res = &model.AuthResponse{
|
||||
Message: `Logged in successfully`,
|
||||
AccessToken: &accessToken,
|
||||
AccessTokenExpiresAt: &expiresAt,
|
||||
User: &model.User{
|
||||
ID: userIdStr,
|
||||
Email: user.Email,
|
||||
Image: &user.Image,
|
||||
FirstName: &user.FirstName,
|
||||
LastName: &user.LastName,
|
||||
SignupMethod: user.SignupMethod,
|
||||
EmailVerifiedAt: &user.EmailVerifiedAt,
|
||||
Roles: strings.Split(user.Roles, ","),
|
||||
CreatedAt: &user.CreatedAt,
|
||||
UpdatedAt: &user.UpdatedAt,
|
||||
},
|
||||
ExpiresAt: &expiresAt,
|
||||
User: utils.GetResponseUserData(user),
|
||||
}
|
||||
|
||||
utils.SetCookie(gc, accessToken)
|
||||
|
@@ -14,10 +14,10 @@ import (
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
)
|
||||
|
||||
func MagicLogin(ctx context.Context, params model.MagicLoginInput) (*model.Response, error) {
|
||||
func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
|
||||
var res *model.Response
|
||||
|
||||
if constants.DISABLE_MAGIC_LOGIN {
|
||||
if constants.DISABLE_MAGIC_LINK_LOGIN {
|
||||
return res, fmt.Errorf(`magic link login is disabled for this instance`)
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func MagicLogin(ctx context.Context, params model.MagicLoginInput) (*model.Respo
|
||||
existingUser, err := db.Mgr.GetUserByEmail(params.Email)
|
||||
|
||||
if err != nil {
|
||||
user.SignupMethod = enum.MagicLink.String()
|
||||
user.SignupMethods = enum.MagicLinkLogin.String()
|
||||
// define roles for new user
|
||||
if len(params.Roles) > 0 {
|
||||
// check if roles exists
|
||||
@@ -86,12 +86,12 @@ func MagicLogin(ctx context.Context, params model.MagicLoginInput) (*model.Respo
|
||||
user.Roles = existingUser.Roles
|
||||
}
|
||||
|
||||
signupMethod := existingUser.SignupMethod
|
||||
if !strings.Contains(signupMethod, enum.MagicLink.String()) {
|
||||
signupMethod = signupMethod + "," + enum.MagicLink.String()
|
||||
signupMethod := existingUser.SignupMethods
|
||||
if !strings.Contains(signupMethod, enum.MagicLinkLogin.String()) {
|
||||
signupMethod = signupMethod + "," + enum.MagicLinkLogin.String()
|
||||
}
|
||||
|
||||
user.SignupMethod = signupMethod
|
||||
user.SignupMethods = signupMethod
|
||||
user, _ = db.Mgr.UpdateUser(user)
|
||||
if err != nil {
|
||||
log.Println("error updating user:", err)
|
||||
@@ -100,7 +100,7 @@ func MagicLogin(ctx context.Context, params model.MagicLoginInput) (*model.Respo
|
||||
|
||||
if !constants.DISABLE_EMAIL_VERIFICATION {
|
||||
// insert verification request
|
||||
verificationType := enum.MagicLink.String()
|
||||
verificationType := enum.MagicLinkLogin.String()
|
||||
token, err := utils.CreateVerificationToken(params.Email, verificationType)
|
||||
if err != nil {
|
||||
log.Println(`error generating token`, err)
|
@@ -3,7 +3,6 @@ package resolvers
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
@@ -41,20 +40,7 @@ func Profile(ctx context.Context) (*model.User, error) {
|
||||
return res, err
|
||||
}
|
||||
|
||||
userIdStr := fmt.Sprintf("%v", user.ID)
|
||||
|
||||
res = &model.User{
|
||||
ID: userIdStr,
|
||||
Email: user.Email,
|
||||
Image: &user.Image,
|
||||
FirstName: &user.FirstName,
|
||||
LastName: &user.LastName,
|
||||
SignupMethod: user.SignupMethod,
|
||||
EmailVerifiedAt: &user.EmailVerifiedAt,
|
||||
Roles: strings.Split(user.Roles, ","),
|
||||
CreatedAt: &user.CreatedAt,
|
||||
UpdatedAt: &user.UpdatedAt,
|
||||
}
|
||||
res = utils.GetResponseUserData(user)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
@@ -20,18 +20,28 @@ func ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput)
|
||||
return res, fmt.Errorf("invalid email")
|
||||
}
|
||||
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(params.Email)
|
||||
if !utils.IsValidVerificationIdentifier(params.Identifier) {
|
||||
return res, fmt.Errorf("invalid identifier")
|
||||
}
|
||||
|
||||
verificationRequest, err := db.Mgr.GetVerificationByEmail(params.Email, params.Identifier)
|
||||
if err != nil {
|
||||
return res, fmt.Errorf(`verification request not found`)
|
||||
}
|
||||
|
||||
token, err := utils.CreateVerificationToken(params.Email, verificationRequest.Identifier)
|
||||
// delete current verification and create new one
|
||||
err = db.Mgr.DeleteVerificationRequest(verificationRequest)
|
||||
if err != nil {
|
||||
log.Println("error deleting verification request:", err)
|
||||
}
|
||||
|
||||
token, err := utils.CreateVerificationToken(params.Email, params.Identifier)
|
||||
if err != nil {
|
||||
log.Println(`error generating token`, err)
|
||||
}
|
||||
db.Mgr.AddVerification(db.VerificationRequest{
|
||||
Token: token,
|
||||
Identifier: verificationRequest.Identifier,
|
||||
Identifier: params.Identifier,
|
||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||
Email: params.Email,
|
||||
})
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
@@ -39,13 +40,19 @@ func ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model
|
||||
}
|
||||
|
||||
password, _ := utils.HashPassword(params.Password)
|
||||
user.Password = password
|
||||
user.Password = &password
|
||||
|
||||
signupMethod := user.SignupMethod
|
||||
signupMethod := user.SignupMethods
|
||||
if !strings.Contains(signupMethod, enum.BasicAuth.String()) {
|
||||
signupMethod = signupMethod + "," + enum.BasicAuth.String()
|
||||
}
|
||||
user.SignupMethod = signupMethod
|
||||
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)
|
@@ -3,7 +3,6 @@ package resolvers
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
@@ -14,7 +13,7 @@ import (
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
)
|
||||
|
||||
func Token(ctx context.Context, roles []string) (*model.AuthResponse, error) {
|
||||
func Session(ctx context.Context, roles []string) (*model.AuthResponse, error) {
|
||||
var res *model.AuthResponse
|
||||
|
||||
gc, err := utils.GinContextFromContext(ctx)
|
||||
@@ -67,34 +66,15 @@ func Token(ctx context.Context, roles []string) (*model.AuthResponse, error) {
|
||||
session.DeleteVerificationRequest(userIdStr, token)
|
||||
token, expiresAt, _ = utils.CreateAuthToken(user, enum.AccessToken, claimRoles)
|
||||
session.SetToken(userIdStr, token, currentRefreshToken)
|
||||
go func() {
|
||||
sessionData := db.Session{
|
||||
UserID: user.ID,
|
||||
UserAgent: utils.GetUserAgent(gc.Request),
|
||||
IP: utils.GetIP(gc.Request),
|
||||
}
|
||||
|
||||
db.Mgr.AddSession(sessionData)
|
||||
}()
|
||||
utils.CreateSession(user.ID, gc)
|
||||
}
|
||||
|
||||
utils.SetCookie(gc, token)
|
||||
res = &model.AuthResponse{
|
||||
Message: `Token verified`,
|
||||
AccessToken: &token,
|
||||
AccessTokenExpiresAt: &expiresAt,
|
||||
User: &model.User{
|
||||
ID: userIdStr,
|
||||
Email: user.Email,
|
||||
Image: &user.Image,
|
||||
FirstName: &user.FirstName,
|
||||
LastName: &user.LastName,
|
||||
Roles: strings.Split(user.Roles, ","),
|
||||
CreatedAt: &user.CreatedAt,
|
||||
UpdatedAt: &user.UpdatedAt,
|
||||
SignupMethod: user.SignupMethod,
|
||||
EmailVerifiedAt: &user.EmailVerifiedAt,
|
||||
},
|
||||
ExpiresAt: &expiresAt,
|
||||
User: utils.GetResponseUserData(user),
|
||||
}
|
||||
return res, nil
|
||||
}
|
@@ -26,7 +26,7 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
|
||||
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
|
||||
}
|
||||
if params.ConfirmPassword != params.Password {
|
||||
return res, fmt.Errorf(`passowrd and confirm password does not match`)
|
||||
return res, fmt.Errorf(`password and confirm password does not match`)
|
||||
}
|
||||
|
||||
params.Email = strings.ToLower(params.Email)
|
||||
@@ -35,6 +35,19 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
|
||||
return res, fmt.Errorf(`invalid email address`)
|
||||
}
|
||||
|
||||
// find user with email
|
||||
existingUser, err := db.Mgr.GetUserByEmail(params.Email)
|
||||
if err != nil {
|
||||
log.Println("user with email " + params.Email + " not found")
|
||||
}
|
||||
|
||||
if existingUser.EmailVerifiedAt != nil {
|
||||
// email is verified
|
||||
return res, fmt.Errorf(`%s has already signed up`, params.Email)
|
||||
} else if existingUser.ID != "" && existingUser.EmailVerifiedAt == nil {
|
||||
return res, fmt.Errorf("%s has already signed up. please complete the email verification process or reset the password", params.Email)
|
||||
}
|
||||
|
||||
inputRoles := []string{}
|
||||
|
||||
if len(params.Roles) > 0 {
|
||||
@@ -48,16 +61,6 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
|
||||
inputRoles = constants.DEFAULT_ROLES
|
||||
}
|
||||
|
||||
// find user with email
|
||||
existingUser, err := db.Mgr.GetUserByEmail(params.Email)
|
||||
if err != nil {
|
||||
log.Println("user with email " + params.Email + " not found")
|
||||
}
|
||||
|
||||
if existingUser.EmailVerifiedAt > 0 {
|
||||
// email is verified
|
||||
return res, fmt.Errorf(`you have already signed up. Please login`)
|
||||
}
|
||||
user := db.User{
|
||||
Email: params.Email,
|
||||
}
|
||||
@@ -65,19 +68,44 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
|
||||
user.Roles = strings.Join(inputRoles, ",")
|
||||
|
||||
password, _ := utils.HashPassword(params.Password)
|
||||
user.Password = password
|
||||
user.Password = &password
|
||||
|
||||
if params.FirstName != nil {
|
||||
user.FirstName = *params.FirstName
|
||||
if params.GivenName != nil {
|
||||
user.GivenName = params.GivenName
|
||||
}
|
||||
|
||||
if params.LastName != nil {
|
||||
user.LastName = *params.LastName
|
||||
if params.FamilyName != nil {
|
||||
user.FamilyName = params.FamilyName
|
||||
}
|
||||
|
||||
user.SignupMethod = enum.BasicAuth.String()
|
||||
if params.MiddleName != nil {
|
||||
user.MiddleName = params.MiddleName
|
||||
}
|
||||
|
||||
if params.Nickname != nil {
|
||||
user.Nickname = params.Nickname
|
||||
}
|
||||
|
||||
if params.Gender != nil {
|
||||
user.Gender = params.Gender
|
||||
}
|
||||
|
||||
if params.Birthdate != nil {
|
||||
user.Birthdate = params.Birthdate
|
||||
}
|
||||
|
||||
if params.PhoneNumber != nil {
|
||||
user.PhoneNumber = params.PhoneNumber
|
||||
}
|
||||
|
||||
if params.Picture != nil {
|
||||
user.Picture = params.Picture
|
||||
}
|
||||
|
||||
user.SignupMethods = enum.BasicAuth.String()
|
||||
if constants.DISABLE_EMAIL_VERIFICATION {
|
||||
user.EmailVerifiedAt = time.Now().Unix()
|
||||
now := time.Now().Unix()
|
||||
user.EmailVerifiedAt = &now
|
||||
}
|
||||
user, err = db.Mgr.AddUser(user)
|
||||
if err != nil {
|
||||
@@ -85,18 +113,7 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
|
||||
}
|
||||
userIdStr := fmt.Sprintf("%v", user.ID)
|
||||
roles := strings.Split(user.Roles, ",")
|
||||
userToReturn := &model.User{
|
||||
ID: userIdStr,
|
||||
Email: user.Email,
|
||||
Image: &user.Image,
|
||||
FirstName: &user.FirstName,
|
||||
LastName: &user.LastName,
|
||||
SignupMethod: user.SignupMethod,
|
||||
EmailVerifiedAt: &user.EmailVerifiedAt,
|
||||
Roles: strings.Split(user.Roles, ","),
|
||||
CreatedAt: &user.CreatedAt,
|
||||
UpdatedAt: &user.UpdatedAt,
|
||||
}
|
||||
userToReturn := utils.GetResponseUserData(user)
|
||||
|
||||
if !constants.DISABLE_EMAIL_VERIFICATION {
|
||||
// insert verification request
|
||||
@@ -128,19 +145,11 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
|
||||
accessToken, expiresAt, _ := utils.CreateAuthToken(user, enum.AccessToken, roles)
|
||||
|
||||
session.SetToken(userIdStr, accessToken, refreshToken)
|
||||
go func() {
|
||||
sessionData := db.Session{
|
||||
UserID: user.ID,
|
||||
UserAgent: utils.GetUserAgent(gc.Request),
|
||||
IP: utils.GetIP(gc.Request),
|
||||
}
|
||||
|
||||
db.Mgr.AddSession(sessionData)
|
||||
}()
|
||||
utils.CreateSession(user.ID, gc)
|
||||
res = &model.AuthResponse{
|
||||
Message: `Signed up successfully.`,
|
||||
AccessToken: &accessToken,
|
||||
AccessTokenExpiresAt: &expiresAt,
|
||||
ExpiresAt: &expiresAt,
|
||||
User: userToReturn,
|
||||
}
|
||||
|
||||
|
@@ -40,7 +40,7 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
|
||||
}
|
||||
|
||||
// validate if all params are not empty
|
||||
if params.FirstName == nil && params.LastName == nil && params.Image == nil && params.OldPassword == nil && params.Email == nil {
|
||||
if params.GivenName == nil && params.FamilyName == nil && params.Picture == nil && params.MiddleName == nil && params.Nickname == nil && params.OldPassword == nil && params.Email == nil && params.Birthdate == nil && params.Gender == nil && params.PhoneNumber == nil {
|
||||
return res, fmt.Errorf("please enter atleast one param to update")
|
||||
}
|
||||
|
||||
@@ -50,20 +50,40 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
|
||||
return res, err
|
||||
}
|
||||
|
||||
if params.FirstName != nil && user.FirstName != *params.FirstName {
|
||||
user.FirstName = *params.FirstName
|
||||
if params.GivenName != nil && user.GivenName != params.GivenName {
|
||||
user.GivenName = params.GivenName
|
||||
}
|
||||
|
||||
if params.LastName != nil && user.LastName != *params.LastName {
|
||||
user.LastName = *params.LastName
|
||||
if params.FamilyName != nil && user.FamilyName != params.FamilyName {
|
||||
user.FamilyName = params.FamilyName
|
||||
}
|
||||
|
||||
if params.Image != nil && user.Image != *params.Image {
|
||||
user.Image = *params.Image
|
||||
if params.MiddleName != nil && user.MiddleName != params.MiddleName {
|
||||
user.MiddleName = params.MiddleName
|
||||
}
|
||||
|
||||
if params.Nickname != nil && user.Nickname != params.Nickname {
|
||||
user.Nickname = params.Nickname
|
||||
}
|
||||
|
||||
if params.Birthdate != nil && user.Birthdate != params.Birthdate {
|
||||
user.Birthdate = params.Birthdate
|
||||
}
|
||||
|
||||
if params.Gender != nil && user.Gender != params.Gender {
|
||||
user.Gender = params.Gender
|
||||
}
|
||||
|
||||
if params.PhoneNumber != nil && user.PhoneNumber != params.PhoneNumber {
|
||||
user.PhoneNumber = params.PhoneNumber
|
||||
}
|
||||
|
||||
if params.Picture != nil && user.Picture != params.Picture {
|
||||
user.Picture = params.Picture
|
||||
}
|
||||
|
||||
if params.OldPassword != nil {
|
||||
if err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(*params.OldPassword)); err != nil {
|
||||
if err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(*params.OldPassword)); err != nil {
|
||||
return res, fmt.Errorf("incorrect old password")
|
||||
}
|
||||
|
||||
@@ -81,7 +101,7 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
|
||||
|
||||
password, _ := utils.HashPassword(*params.NewPassword)
|
||||
|
||||
user.Password = password
|
||||
user.Password = &password
|
||||
}
|
||||
|
||||
hasEmailChanged := false
|
||||
@@ -93,7 +113,8 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
|
||||
}
|
||||
newEmail := strings.ToLower(*params.Email)
|
||||
// check if user with new email exists
|
||||
_, err = db.Mgr.GetUserByEmail(newEmail)
|
||||
_, err := db.Mgr.GetUserByEmail(newEmail)
|
||||
|
||||
// err = nil means user exists
|
||||
if err == nil {
|
||||
return res, fmt.Errorf("user with this email address already exists")
|
||||
@@ -103,7 +124,7 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
|
||||
utils.DeleteCookie(gc)
|
||||
|
||||
user.Email = newEmail
|
||||
user.EmailVerifiedAt = 0
|
||||
user.EmailVerifiedAt = nil
|
||||
hasEmailChanged = true
|
||||
// insert verification request
|
||||
verificationType := enum.UpdateEmail.String()
|
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
)
|
||||
|
||||
func AdminUpdateUser(ctx context.Context, params model.AdminUpdateUserInput) (*model.User, error) {
|
||||
func UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error) {
|
||||
gc, err := utils.GinContextFromContext(ctx)
|
||||
var res *model.User
|
||||
if err != nil {
|
||||
@@ -26,7 +26,7 @@ func AdminUpdateUser(ctx context.Context, params model.AdminUpdateUserInput) (*m
|
||||
return res, fmt.Errorf("unauthorized")
|
||||
}
|
||||
|
||||
if params.FirstName == nil && params.LastName == nil && params.Image == nil && params.Email == nil && params.Roles == nil {
|
||||
if params.GivenName == nil && params.FamilyName == nil && params.Picture == nil && params.MiddleName == nil && params.Nickname == nil && params.Email == nil && params.Birthdate == nil && params.Gender == nil && params.PhoneNumber == nil && params.Roles == nil {
|
||||
return res, fmt.Errorf("please enter atleast one param to update")
|
||||
}
|
||||
|
||||
@@ -35,16 +35,36 @@ func AdminUpdateUser(ctx context.Context, params model.AdminUpdateUserInput) (*m
|
||||
return res, fmt.Errorf(`User not found`)
|
||||
}
|
||||
|
||||
if params.FirstName != nil && user.FirstName != *params.FirstName {
|
||||
user.FirstName = *params.FirstName
|
||||
if params.GivenName != nil && user.GivenName != params.GivenName {
|
||||
user.GivenName = params.GivenName
|
||||
}
|
||||
|
||||
if params.LastName != nil && user.LastName != *params.LastName {
|
||||
user.LastName = *params.LastName
|
||||
if params.FamilyName != nil && user.FamilyName != params.FamilyName {
|
||||
user.FamilyName = params.FamilyName
|
||||
}
|
||||
|
||||
if params.Image != nil && user.Image != *params.Image {
|
||||
user.Image = *params.Image
|
||||
if params.MiddleName != nil && user.MiddleName != params.MiddleName {
|
||||
user.MiddleName = params.MiddleName
|
||||
}
|
||||
|
||||
if params.Nickname != nil && user.Nickname != params.Nickname {
|
||||
user.Nickname = params.Nickname
|
||||
}
|
||||
|
||||
if params.Birthdate != nil && user.Birthdate != params.Birthdate {
|
||||
user.Birthdate = params.Birthdate
|
||||
}
|
||||
|
||||
if params.Gender != nil && user.Gender != params.Gender {
|
||||
user.Gender = params.Gender
|
||||
}
|
||||
|
||||
if params.PhoneNumber != nil && user.PhoneNumber != params.PhoneNumber {
|
||||
user.PhoneNumber = params.PhoneNumber
|
||||
}
|
||||
|
||||
if params.Picture != nil && user.Picture != params.Picture {
|
||||
user.Picture = params.Picture
|
||||
}
|
||||
|
||||
if params.Email != nil && user.Email != *params.Email {
|
||||
@@ -64,7 +84,7 @@ func AdminUpdateUser(ctx context.Context, params model.AdminUpdateUserInput) (*m
|
||||
utils.DeleteCookie(gc)
|
||||
|
||||
user.Email = newEmail
|
||||
user.EmailVerifiedAt = 0
|
||||
user.EmailVerifiedAt = nil
|
||||
// insert verification request
|
||||
verificationType := enum.UpdateEmail.String()
|
||||
token, err := utils.CreateVerificationToken(newEmail, verificationType)
|
||||
@@ -117,9 +137,9 @@ func AdminUpdateUser(ctx context.Context, params model.AdminUpdateUserInput) (*m
|
||||
res = &model.User{
|
||||
ID: params.ID,
|
||||
Email: user.Email,
|
||||
Image: &user.Image,
|
||||
FirstName: &user.FirstName,
|
||||
LastName: &user.LastName,
|
||||
Picture: user.Picture,
|
||||
GivenName: user.GivenName,
|
||||
FamilyName: user.FamilyName,
|
||||
Roles: strings.Split(user.Roles, ","),
|
||||
CreatedAt: &user.CreatedAt,
|
||||
UpdatedAt: &user.UpdatedAt,
|
@@ -3,7 +3,6 @@ package resolvers
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
@@ -27,17 +26,7 @@ func Users(ctx context.Context) ([]*model.User, error) {
|
||||
}
|
||||
|
||||
for i := 0; i < len(users); i++ {
|
||||
res = append(res, &model.User{
|
||||
ID: fmt.Sprintf("%v", users[i].ID),
|
||||
Email: users[i].Email,
|
||||
SignupMethod: users[i].SignupMethod,
|
||||
FirstName: &users[i].FirstName,
|
||||
LastName: &users[i].LastName,
|
||||
EmailVerifiedAt: &users[i].EmailVerifiedAt,
|
||||
Roles: strings.Split(users[i].Roles, ","),
|
||||
CreatedAt: &users[i].CreatedAt,
|
||||
UpdatedAt: &users[i].UpdatedAt,
|
||||
})
|
||||
res = append(res, utils.GetResponseUserData(users[i]))
|
||||
}
|
||||
|
||||
return res, nil
|
||||
|
@@ -37,44 +37,25 @@ func VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.Aut
|
||||
}
|
||||
|
||||
// update email_verified_at in users table
|
||||
user.EmailVerifiedAt = time.Now().Unix()
|
||||
now := time.Now().Unix()
|
||||
user.EmailVerifiedAt = &now
|
||||
db.Mgr.UpdateUser(user)
|
||||
// delete from verification table
|
||||
db.Mgr.DeleteVerificationRequest(verificationRequest)
|
||||
|
||||
userIdStr := fmt.Sprintf("%v", user.ID)
|
||||
roles := strings.Split(user.Roles, ",")
|
||||
refreshToken, _, _ := utils.CreateAuthToken(user, enum.RefreshToken, roles)
|
||||
|
||||
accessToken, expiresAt, _ := utils.CreateAuthToken(user, enum.AccessToken, roles)
|
||||
|
||||
session.SetToken(userIdStr, accessToken, refreshToken)
|
||||
go func() {
|
||||
sessionData := db.Session{
|
||||
UserID: user.ID,
|
||||
UserAgent: utils.GetUserAgent(gc.Request),
|
||||
IP: utils.GetIP(gc.Request),
|
||||
}
|
||||
|
||||
db.Mgr.AddSession(sessionData)
|
||||
}()
|
||||
session.SetToken(user.ID, accessToken, refreshToken)
|
||||
utils.CreateSession(user.ID, gc)
|
||||
|
||||
res = &model.AuthResponse{
|
||||
Message: `Email verified successfully.`,
|
||||
AccessToken: &accessToken,
|
||||
AccessTokenExpiresAt: &expiresAt,
|
||||
User: &model.User{
|
||||
ID: userIdStr,
|
||||
Email: user.Email,
|
||||
Image: &user.Image,
|
||||
FirstName: &user.FirstName,
|
||||
LastName: &user.LastName,
|
||||
SignupMethod: user.SignupMethod,
|
||||
EmailVerifiedAt: &user.EmailVerifiedAt,
|
||||
Roles: strings.Split(user.Roles, ","),
|
||||
CreatedAt: &user.CreatedAt,
|
||||
UpdatedAt: &user.UpdatedAt,
|
||||
},
|
||||
ExpiresAt: &expiresAt,
|
||||
User: utils.GetResponseUserData(user),
|
||||
}
|
||||
|
||||
utils.SetCookie(gc, accessToken)
|
23
server/router/router.go
Normal file
23
server/router/router.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/authorizerdev/authorizer/server/handlers"
|
||||
"github.com/authorizerdev/authorizer/server/middlewares"
|
||||
"github.com/gin-contrib/location"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func InitRouter() *gin.Engine {
|
||||
router := gin.Default()
|
||||
router.Use(location.Default())
|
||||
router.Use(middlewares.GinContextToContextMiddleware())
|
||||
router.Use(middlewares.CORSMiddleware())
|
||||
|
||||
router.GET("/", handlers.PlaygroundHandler())
|
||||
router.POST("/graphql", handlers.GraphqlHandler())
|
||||
router.GET("/verify_email", handlers.VerifyEmailHandler())
|
||||
router.GET("/oauth_login/:oauth_provider", handlers.OAuthLoginHandler())
|
||||
router.GET("/oauth_callback/:oauth_provider", handlers.OAuthCallbackHandler())
|
||||
|
||||
return router
|
||||
}
|
@@ -26,34 +26,31 @@ func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (st
|
||||
|
||||
expiresAt := time.Now().Add(expiryBound).Unix()
|
||||
|
||||
resUser := GetResponseUserData(user)
|
||||
userBytes, _ := json.Marshal(&resUser)
|
||||
var userMap map[string]interface{}
|
||||
json.Unmarshal(userBytes, &userMap)
|
||||
|
||||
customClaims := jwt.MapClaims{
|
||||
"exp": expiresAt,
|
||||
"iat": time.Now().Unix(),
|
||||
"token_type": tokenType.String(),
|
||||
"email": user.Email,
|
||||
"id": user.ID,
|
||||
"allowed_roles": strings.Split(user.Roles, ","),
|
||||
constants.JWT_ROLE_CLAIM: roles,
|
||||
}
|
||||
|
||||
// check for the extra access token script
|
||||
|
||||
accessTokenScript := os.Getenv("CUSTOM_ACCESS_TOKEN_SCRIPT")
|
||||
if accessTokenScript != "" {
|
||||
userInfo := map[string]interface{}{
|
||||
"id": user.ID,
|
||||
"email": user.Email,
|
||||
"firstName": user.FirstName,
|
||||
"lastName": user.LastName,
|
||||
"image": user.Image,
|
||||
"roles": strings.Split(user.Roles, ","),
|
||||
"signUpMethods": strings.Split(user.SignupMethod, ","),
|
||||
for k, v := range userMap {
|
||||
if k != "roles" {
|
||||
customClaims[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// check for the extra access token script
|
||||
accessTokenScript := os.Getenv("CUSTOM_ACCESS_TOKEN_SCRIPT")
|
||||
if accessTokenScript != "" {
|
||||
vm := otto.New()
|
||||
userBytes, _ := json.Marshal(userInfo)
|
||||
claimBytes, _ := json.Marshal(customClaims)
|
||||
|
||||
claimBytes, _ := json.Marshal(customClaims)
|
||||
vm.Run(fmt.Sprintf(`
|
||||
var user = %s;
|
||||
var tokenPayload = %s;
|
@@ -10,7 +10,7 @@ import (
|
||||
func SetCookie(gc *gin.Context, token string) {
|
||||
secure := true
|
||||
httpOnly := true
|
||||
host := GetHostName(constants.AUTHORIZER_URL)
|
||||
host, _ := GetHostParts(constants.AUTHORIZER_URL)
|
||||
domain := GetDomainName(constants.AUTHORIZER_URL)
|
||||
if domain != "localhost" {
|
||||
domain = "." + domain
|
||||
@@ -37,7 +37,7 @@ func DeleteCookie(gc *gin.Context) {
|
||||
secure := true
|
||||
httpOnly := true
|
||||
|
||||
host := GetDomainName(constants.AUTHORIZER_URL)
|
||||
host, _ := GetHostParts(constants.AUTHORIZER_URL)
|
||||
domain := GetDomainName(constants.AUTHORIZER_URL)
|
||||
if domain != "localhost" {
|
||||
domain = "." + domain
|
||||
|
16
server/utils/create_session.go
Normal file
16
server/utils/create_session.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func CreateSession(userId string, c *gin.Context) {
|
||||
sessionData := db.Session{
|
||||
UserID: userId,
|
||||
UserAgent: GetUserAgent(c.Request),
|
||||
IP: GetIP(c.Request),
|
||||
}
|
||||
|
||||
db.Mgr.AddSession(sessionData)
|
||||
}
|
@@ -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
|
||||
}
|
||||
|
32
server/utils/get_response_user_data.go
Normal file
32
server/utils/get_response_user_data.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
)
|
||||
|
||||
func GetResponseUserData(user db.User) *model.User {
|
||||
isEmailVerified := user.EmailVerifiedAt != nil
|
||||
isPhoneVerified := user.PhoneNumberVerifiedAt != nil
|
||||
return &model.User{
|
||||
ID: user.ID,
|
||||
Email: user.Email,
|
||||
EmailVerified: isEmailVerified,
|
||||
SignupMethods: user.SignupMethods,
|
||||
GivenName: user.GivenName,
|
||||
FamilyName: user.FamilyName,
|
||||
MiddleName: user.MiddleName,
|
||||
Nickname: user.Nickname,
|
||||
PreferredUsername: &user.Email,
|
||||
Gender: user.Gender,
|
||||
Birthdate: user.Birthdate,
|
||||
PhoneNumber: user.PhoneNumber,
|
||||
PhoneNumberVerified: &isPhoneVerified,
|
||||
Picture: user.Picture,
|
||||
Roles: strings.Split(user.Roles, ","),
|
||||
CreatedAt: &user.CreatedAt,
|
||||
UpdatedAt: &user.UpdatedAt,
|
||||
}
|
||||
}
|
@@ -11,11 +11,10 @@ func GetMetaInfo() model.Meta {
|
||||
return model.Meta{
|
||||
Version: constants.VERSION,
|
||||
IsGoogleLoginEnabled: constants.GOOGLE_CLIENT_ID != "" && constants.GOOGLE_CLIENT_SECRET != "",
|
||||
IsGithubLoginEnabled: constants.GITHUB_CLIENT_ID != "" && constants.GOOGLE_CLIENT_SECRET != "",
|
||||
IsGithubLoginEnabled: constants.GITHUB_CLIENT_ID != "" && constants.GITHUB_CLIENT_SECRET != "",
|
||||
IsFacebookLoginEnabled: constants.FACEBOOK_CLIENT_ID != "" && constants.FACEBOOK_CLIENT_SECRET != "",
|
||||
IsTwitterLoginEnabled: constants.TWITTER_CLIENT_ID != "" && constants.TWITTER_CLIENT_SECRET != "",
|
||||
IsBasicAuthenticationEnabled: !constants.DISABLE_BASIC_AUTHENTICATION,
|
||||
IsEmailVerificationEnabled: !constants.DISABLE_EMAIL_VERIFICATION,
|
||||
IsMagicLoginEnabled: !constants.DISABLE_MAGIC_LOGIN,
|
||||
IsMagicLinkLoginEnabled: !constants.DISABLE_MAGIC_LINK_LOGIN,
|
||||
}
|
||||
}
|
||||
|
@@ -5,21 +5,32 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetHostName function to get hostname
|
||||
func GetHostName(auth_url string) string {
|
||||
u, err := url.Parse(auth_url)
|
||||
// GetHostName function returns hostname and port
|
||||
func GetHostParts(uri string) (string, string) {
|
||||
tempURI := uri
|
||||
if !strings.HasPrefix(tempURI, "http") && strings.HasPrefix(tempURI, "https") {
|
||||
tempURI = "https://" + tempURI
|
||||
}
|
||||
|
||||
u, err := url.Parse(tempURI)
|
||||
if err != nil {
|
||||
return `localhost`
|
||||
return "localhost", "8080"
|
||||
}
|
||||
|
||||
host := u.Hostname()
|
||||
port := u.Port()
|
||||
|
||||
return host
|
||||
return host, port
|
||||
}
|
||||
|
||||
// GetDomainName function to get domain name
|
||||
func GetDomainName(auth_url string) string {
|
||||
u, err := url.Parse(auth_url)
|
||||
func GetDomainName(uri string) string {
|
||||
tempURI := uri
|
||||
if !strings.HasPrefix(tempURI, "http") && strings.HasPrefix(tempURI, "https") {
|
||||
tempURI = "https://" + tempURI
|
||||
}
|
||||
|
||||
u, err := url.Parse(tempURI)
|
||||
if err != nil {
|
||||
return `localhost`
|
||||
}
|
||||
|
@@ -1,25 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetHostName(t *testing.T) {
|
||||
authorizer_url := "http://test.herokuapp.com"
|
||||
|
||||
got := GetHostName(authorizer_url)
|
||||
want := "test.herokuapp.com"
|
||||
|
||||
assert.Equal(t, got, want, "hostname should be equal")
|
||||
}
|
||||
|
||||
func TestGetDomainName(t *testing.T) {
|
||||
authorizer_url := "http://test.herokuapp.com"
|
||||
|
||||
got := GetDomainName(authorizer_url)
|
||||
want := "herokuapp.com"
|
||||
|
||||
assert.Equal(t, got, want, "domain name should be equal")
|
||||
}
|
@@ -2,9 +2,11 @@ package utils
|
||||
|
||||
import (
|
||||
"net/mail"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -13,16 +15,32 @@ func IsValidEmail(email string) bool {
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func IsValidRedirectURL(url string) bool {
|
||||
func IsValidOrigin(url string) bool {
|
||||
if len(constants.ALLOWED_ORIGINS) == 1 && constants.ALLOWED_ORIGINS[0] == "*" {
|
||||
return true
|
||||
}
|
||||
|
||||
hasValidURL := false
|
||||
urlDomain := GetDomainName(url)
|
||||
hostName, port := GetHostParts(url)
|
||||
currentOrigin := hostName + ":" + port
|
||||
|
||||
for _, val := range constants.ALLOWED_ORIGINS {
|
||||
if strings.Contains(val, urlDomain) {
|
||||
for _, origin := range constants.ALLOWED_ORIGINS {
|
||||
replacedString := origin
|
||||
// if has regex whitelisted domains
|
||||
if strings.Contains(origin, "*") {
|
||||
replacedString = strings.Replace(origin, ".", "\\.", -1)
|
||||
replacedString = strings.Replace(replacedString, "*", ".*", -1)
|
||||
|
||||
if strings.HasPrefix(replacedString, ".*") {
|
||||
replacedString += "\\b"
|
||||
}
|
||||
|
||||
if strings.HasSuffix(replacedString, ".*") {
|
||||
replacedString = "\\b" + replacedString
|
||||
}
|
||||
}
|
||||
|
||||
if matched, _ := regexp.MatchString(replacedString, currentOrigin); matched {
|
||||
hasValidURL = true
|
||||
break
|
||||
}
|
||||
@@ -52,6 +70,13 @@ func IsValidRoles(userRoles []string, roles []string) bool {
|
||||
return valid
|
||||
}
|
||||
|
||||
func IsValidVerificationIdentifier(identifier string) bool {
|
||||
if identifier != enum.BasicAuthSignup.String() && identifier != enum.ForgotPassword.String() && identifier != enum.UpdateEmail.String() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func IsStringArrayEqual(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
|
@@ -1,17 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIsValidEmail(t *testing.T) {
|
||||
validEmail := "lakhan@gmail.com"
|
||||
invalidEmail1 := "lakhan"
|
||||
invalidEmail2 := "lakhan.me"
|
||||
|
||||
assert.True(t, IsValidEmail(validEmail), "it should be valid email")
|
||||
assert.False(t, IsValidEmail(invalidEmail1), "it should be invalid email")
|
||||
assert.False(t, IsValidEmail(invalidEmail2), "it should be invalid email")
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user