first time go in to cloud repo
This commit is contained in:
commit
594788380c
|
|
@ -0,0 +1,5 @@
|
|||
MONGO_URI="mongodb://adminLinh:linhporo1@localhost:27017/linhporo1?authSource=admin"
|
||||
API_TEST_PORT=":8080"
|
||||
REDIS_URI="redis://localhost:6379/0"
|
||||
STMP_PASS="btmp judz ebys pfxw"
|
||||
EMAIL_VERIFY_SECRET="WDc&4+&vYP(n'}?LHNE#5M?IE|g(c812"
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="myValues">
|
||||
<value>
|
||||
<list size="1">
|
||||
<item index="0" class="java.lang.String" itemvalue="src" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myCustomValuesEnabled" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="HtmlUnknownTag" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="myValues">
|
||||
<value>
|
||||
<list size="7">
|
||||
<item index="0" class="java.lang.String" itemvalue="nobr" />
|
||||
<item index="1" class="java.lang.String" itemvalue="noembed" />
|
||||
<item index="2" class="java.lang.String" itemvalue="comment" />
|
||||
<item index="3" class="java.lang.String" itemvalue="noscript" />
|
||||
<item index="4" class="java.lang.String" itemvalue="embed" />
|
||||
<item index="5" class="java.lang.String" itemvalue="script" />
|
||||
<item index="6" class="java.lang.String" itemvalue="img" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myCustomValuesEnabled" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/go-restapi-parttern.iml" filepath="$PROJECT_DIR$/.idea/go-restapi-parttern.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>JS Bin</title>
|
||||
</head>
|
||||
<body style="background-color: #f2f5f8;">
|
||||
<div style="max-width: 700px; margin: 0 auto">
|
||||
<table
|
||||
align="center"
|
||||
role="presentation"
|
||||
cellspacing="0"
|
||||
cellpadding="0"
|
||||
border="0"
|
||||
width="100%"
|
||||
style="margin: auto"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<table
|
||||
align="center"
|
||||
role="presentation"
|
||||
cellspacing="0"
|
||||
cellpadding="0"
|
||||
border="0"
|
||||
width="100%"
|
||||
style="margin: auto"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding: 30px 0; text-align: center"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
height: 4px;
|
||||
text-align: center;
|
||||
background: rgb(255, 122, 89);
|
||||
--darkreader-inline-bgimage: initial;
|
||||
--darkreader-inline-bgcolor: #971e00;
|
||||
"
|
||||
data-darkreader-inline-bgimage=""
|
||||
data-darkreader-inline-bgcolor=""
|
||||
></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
background: rgb(255, 255, 255);
|
||||
width: 100%;
|
||||
padding: 40px 0;
|
||||
min-width: 100%;
|
||||
color: rgb(255, 255, 255);
|
||||
--darkreader-inline-bgimage: initial;
|
||||
--darkreader-inline-bgcolor: #181a1b;
|
||||
--darkreader-inline-color: #e8e6e3;
|
||||
"
|
||||
data-darkreader-inline-bgimage=""
|
||||
data-darkreader-inline-bgcolor=""
|
||||
data-darkreader-inline-color=""
|
||||
>
|
||||
<img
|
||||
src="https://pos.nvncdn.net/d0f3ca-7136/store/20230906_9BHMhQjv.png"
|
||||
width="120"
|
||||
height=""
|
||||
alt="alt_text"
|
||||
border="0"
|
||||
style="
|
||||
height: auto;
|
||||
font-family: sans-serif;
|
||||
font-size: 15px;
|
||||
line-height: 15px;
|
||||
color: rgb(85, 85, 85);
|
||||
margin: auto;
|
||||
display: block;
|
||||
--darkreader-inline-color: #b2aca2;
|
||||
"
|
||||
class="CToWUd"
|
||||
data-bit="iit"
|
||||
data-darkreader-inline-color=""
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
height: 1px;
|
||||
background: rgb(255, 255, 255);
|
||||
--darkreader-inline-bgimage: initial;
|
||||
--darkreader-inline-bgcolor: #181a1b;
|
||||
"
|
||||
data-darkreader-inline-bgimage=""
|
||||
data-darkreader-inline-bgcolor=""
|
||||
>
|
||||
<div
|
||||
style="
|
||||
height: 1px;
|
||||
max-width: 500px;
|
||||
margin: auto;
|
||||
background: rgb(234, 240, 246);
|
||||
--darkreader-inline-bgimage: initial;
|
||||
--darkreader-inline-bgcolor: #202325;
|
||||
"
|
||||
data-darkreader-inline-bgimage=""
|
||||
data-darkreader-inline-bgcolor=""
|
||||
></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
background-color: rgb(255, 255, 255);
|
||||
--darkreader-inline-bgcolor: #181a1b;
|
||||
"
|
||||
data-darkreader-inline-bgcolor=""
|
||||
>
|
||||
<table
|
||||
role="presentation"
|
||||
cellspacing="0"
|
||||
cellpadding="0"
|
||||
border="0"
|
||||
width="100%"
|
||||
style="max-width: 500px; margin: auto"
|
||||
>
|
||||
<tbody></tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: rgb(66, 91, 118);
|
||||
--darkreader-inline-color: #97b0c5;
|
||||
"
|
||||
data-darkreader-inline-color=""
|
||||
>
|
||||
<h1
|
||||
style="
|
||||
text-align: center;
|
||||
margin: 30px 0;
|
||||
font-family: 'Helvetica Neue', 'Lexend Deca',
|
||||
Arial, Helvetica, sans-serif;
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
color: rgb(66, 91, 118);
|
||||
font-weight: bold;
|
||||
--darkreader-inline-color: #97b0c5;
|
||||
"
|
||||
data-darkreader-inline-color=""
|
||||
>
|
||||
Verify your email.
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
style="
|
||||
width: 100vw;
|
||||
max-width: 700px;
|
||||
height: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
"
|
||||
>
|
||||
<img
|
||||
src="https://res.cloudinary.com/practicaldev/image/fetch/s--1II67h1R--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://faruknasir.com/images/blog/2021/verification_url.png"
|
||||
alt="verifi-piture"
|
||||
width="420"
|
||||
height=""
|
||||
style="margin: auto"
|
||||
/>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
padding: 0;
|
||||
font-family: 'Helvetica Neue', 'Lexend Deca',
|
||||
Arial, Helvetica, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
color: rgb(66, 91, 118);
|
||||
--darkreader-inline-color: #97b0c5;
|
||||
"
|
||||
data-darkreader-inline-color=""
|
||||
>
|
||||
<p style="text-align: center; margin: 0">
|
||||
Enter this code in your browser to verify your
|
||||
email:
|
||||
</p>
|
||||
<p
|
||||
style="
|
||||
margin: 30px 0 0;
|
||||
font-size: 40px;
|
||||
line-height: 40px;
|
||||
letter-spacing: 4px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
text-align: center;
|
||||
"
|
||||
>
|
||||
{{.Otp}}
|
||||
</p>
|
||||
<p
|
||||
style="
|
||||
margin: 10px 0 30px;
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
text-align: center;
|
||||
color: rgb(81, 111, 144);
|
||||
--darkreader-inline-color: #88a4bc;
|
||||
"
|
||||
data-darkreader-inline-color=""
|
||||
>
|
||||
Code will expire in 24 hours.
|
||||
</p>
|
||||
<p style="text-align: center">
|
||||
Having trouble with the code? Use
|
||||
<a
|
||||
href="{{.AlternativeLink}}"
|
||||
style="
|
||||
color: rgb(0, 141, 163);
|
||||
--darkreader-inline-color: #5ae9ff;
|
||||
"
|
||||
target="_blank"
|
||||
data-saferedirecturl=""
|
||||
data-darkreader-inline-color="{{.AlternativeLink}}"
|
||||
>this link</a
|
||||
>
|
||||
instead.
|
||||
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
aria-hidden="true"
|
||||
height="50"
|
||||
style="
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
display: block;
|
||||
"
|
||||
>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
display: none;
|
||||
padding: 40px 60px 0;
|
||||
font-family: 'Helvetica Neue', 'Lexend Deca',
|
||||
Arial, Helvetica, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
color: rgb(45, 62, 80);
|
||||
--darkreader-inline-color: #aec2d2;
|
||||
"
|
||||
data-darkreader-inline-color=""
|
||||
></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
aria-hidden="true"
|
||||
height="50"
|
||||
style="font-size: 0; line-height: 0"
|
||||
>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table
|
||||
align="center"
|
||||
role="presentation"
|
||||
cellspacing="0"
|
||||
cellpadding="0"
|
||||
border="0"
|
||||
width="100%"
|
||||
style="margin: auto"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
padding: 20px 10%;
|
||||
font-family: 'Helvetica Neue', 'Lexend Deca', Arial,
|
||||
Helvetica, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
color: rgb(124, 152, 182);
|
||||
--darkreader-inline-color: #83a1ba;
|
||||
"
|
||||
data-darkreader-inline-color=""
|
||||
>
|
||||
Not you? If you didn't request a code to sign up for
|
||||
HubSpot, you can safely ignore this email. An account was
|
||||
not created.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
padding: 20px;
|
||||
font-family: 'Helvetica Neue', 'Lexend Deca', Arial,
|
||||
Helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
color: rgb(124, 152, 182);
|
||||
--darkreader-inline-color: #83a1ba;
|
||||
"
|
||||
data-darkreader-inline-color=""
|
||||
>
|
||||
WliafDew, Inc.<br /><span
|
||||
>72 Truong Quyen, 3nd Floor<br />Tp. Ho Chi Minh, VN
|
||||
020319</span
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
module linhdevtran99/rest-api
|
||||
|
||||
go 1.21.0
|
||||
|
||||
require (
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/go-mail/mail v2.3.1+incompatible // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.16.0 // indirect
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||
github.com/pquerna/otp v1.4.0 // indirect
|
||||
github.com/redis/go-redis/v9 v9.3.0 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||
go.mongodb.org/mongo-driver v1.13.0 // indirect
|
||||
golang.org/x/crypto v0.7.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
)
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/go-mail/mail v2.3.1+incompatible h1:UzNOn0k5lpfVtO31cK3hn6I4VEVGhe3lX8AJBAxXExM=
|
||||
github.com/go-mail/mail v2.3.1+incompatible/go.mod h1:VPWjmmNyRsWXQZHVHT3g0YbIINUkSmuKOiLIDkWbL6M=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
|
||||
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
|
||||
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/redis/go-redis/v9 v9.3.0 h1:RiVDjmig62jIWp7Kk4XVLs0hzV6pI3PyTnnL0cnn0u0=
|
||||
github.com/redis/go-redis/v9 v9.3.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
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.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
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.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver v1.13.0 h1:67DgFFjYOCMWdtTEmKFpV3ffWlFnh+CYZ8ZS/tXWUfY=
|
||||
go.mongodb.org/mongo-driver v1.13.0/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/joho/godotenv"
|
||||
"linhdevtran99/rest-api/models"
|
||||
"linhdevtran99/rest-api/rest-api"
|
||||
"linhdevtran99/rest-api/utils"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := godotenv.Load(); err != nil {
|
||||
fmt.Println("No .env file found")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
redisUri := os.Getenv("REDIS_URI")
|
||||
apiTestPort := os.Getenv("API_TEST_PORT")
|
||||
mongoUri := os.Getenv("MONGO_URI")
|
||||
|
||||
if redisUri == "" || apiTestPort == "" || mongoUri == "" {
|
||||
fmt.Println("Redis URI:", redisUri)
|
||||
fmt.Println("API test Port:", apiTestPort)
|
||||
fmt.Println("Mongodb Uri:", mongoUri)
|
||||
log.Fatal("Error in some value")
|
||||
}
|
||||
|
||||
models.Validate = validator.New(validator.WithRequiredStructEnabled())
|
||||
|
||||
utils.InitMongoDriver(mongoUri)
|
||||
|
||||
server := rest_api.NewAPIServer(apiTestPort)
|
||||
utils.RedisClientDriver(redisUri)
|
||||
server.Run()
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"github.com/go-playground/validator/v10"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Mongodb Type
|
||||
type PreusersMongo struct {
|
||||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
||||
Username string `bson:"username" json:"username" `
|
||||
Email string `bson:"email" json:"email"`
|
||||
HashPassword string `bson:"hash_password" json:"hash_password"`
|
||||
PhoneNumber string `bson:"phone_number" json:"phone_number"`
|
||||
CreatedDate time.Time `bson:"created_date" json:"created_date"`
|
||||
VerifySentCount int `bson:"verify_sent_count" json:"verify_sent_count"`
|
||||
}
|
||||
|
||||
type UsersMongo struct {
|
||||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
||||
Username string `bson:"username" json:"username"`
|
||||
Email string `bson:"email" json:"email"`
|
||||
HashPassword string `bson:"hash_password" json:"hash_password"`
|
||||
PhoneNumber string `bson:"phone_number" json:"phone_number"`
|
||||
Active bool `bson:"active" json:"active"`
|
||||
CreatedDate time.Time `bson:"created_date" json:"created_date"`
|
||||
VerifySentCount int `bson:"verify_sent_count" json:"verify_sent_count"`
|
||||
}
|
||||
|
||||
var Validate *validator.Validate
|
||||
|
||||
// API Type
|
||||
type CreateUser struct {
|
||||
Username string `json:"username" validate:"required,min=8,max=20"`
|
||||
Email string `json:"email" validate:"required,email"`
|
||||
Password string `json:"password" validate:"required,min=8,max=20,customPassword"`
|
||||
ConfirmPassword string `json:"confirm_password" validate:"required,eqfield=Password"`
|
||||
PhoneNumber string `json:"phone_number" validate:"required,len=10"`
|
||||
}
|
||||
|
||||
type Users struct {
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
HashPassword string `json:"hash_password"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
Active bool `json:"active"`
|
||||
CreatedDate string `json:"created_date"`
|
||||
ValidDate int `json:"verify_sent_count"`
|
||||
}
|
||||
|
||||
// custom validator list
|
||||
|
||||
func PasswordValidator(fl validator.FieldLevel) bool {
|
||||
password := fl.Field().String()
|
||||
|
||||
// Flags to track if at least one symbol and one number are found
|
||||
hasSymbol := false
|
||||
hasNumber := false
|
||||
|
||||
// Check if the password contains at least one symbol and one number
|
||||
for _, char := range password {
|
||||
if strings.ContainsRune("!@#$%^&*()-_=+[]{}|;:'\"<>,.?/~`", char) {
|
||||
hasSymbol = true
|
||||
} else if unicode.IsNumber(char) {
|
||||
hasNumber = true
|
||||
}
|
||||
|
||||
// Break early if both conditions are met
|
||||
if hasSymbol && hasNumber {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
//Interal Type
|
||||
|
||||
type EmailTemplate struct {
|
||||
Otp string `json:"otp"`
|
||||
AlternativeLink string `json:"alternativeLink"`
|
||||
}
|
||||
|
|
@ -0,0 +1,380 @@
|
|||
package rest_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pquerna/otp"
|
||||
"github.com/pquerna/otp/hotp"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"linhdevtran99/rest-api/models"
|
||||
"linhdevtran99/rest-api/utils"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
type APIServer struct {
|
||||
listenAddr string
|
||||
}
|
||||
|
||||
func WriteJSON(w http.ResponseWriter, status int, v any) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
return json.NewEncoder(w).Encode(v)
|
||||
}
|
||||
|
||||
type ApiError struct {
|
||||
Error string
|
||||
}
|
||||
|
||||
// define function apiFn
|
||||
type apiFunc func(http.ResponseWriter, *http.Request) error
|
||||
|
||||
// makeHTTPHandlerFn fn
|
||||
func makeHTTPHandlerFn(fn apiFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := fn(w, r); err != nil {
|
||||
if err := WriteJSON(w, http.StatusInternalServerError, ApiError{Error: err.Error()}); err != nil {
|
||||
fmt.Print(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewAPIServer(listenAddr string) *APIServer {
|
||||
return &APIServer{
|
||||
listenAddr: listenAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func startMuxServer(s *APIServer, router *mux.Router) {
|
||||
log.Println("Listening on", s.listenAddr)
|
||||
|
||||
if err := http.ListenAndServe(s.listenAddr, router); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *APIServer) Run() {
|
||||
router := mux.NewRouter()
|
||||
|
||||
router.HandleFunc("/account/register", makeHTTPHandlerFn(s.registerNewAccount))
|
||||
router.HandleFunc("/account", makeHTTPHandlerFn(s.handleAccount))
|
||||
router.HandleFunc("/test", makeHTTPHandlerFn(s.testCheckUserAndPass))
|
||||
|
||||
startMuxServer(s, router)
|
||||
}
|
||||
|
||||
func (s *APIServer) registerNewAccount(w http.ResponseWriter, r *http.Request) error {
|
||||
if r.Method == http.MethodGet {
|
||||
fmt.Println("API Route Healthy")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *APIServer) testCheckUserAndPass(w http.ResponseWriter, r *http.Request) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
client := utils.MongoDB
|
||||
|
||||
if r.Method == http.MethodGet {
|
||||
fmt.Println("hit")
|
||||
|
||||
//m := mail.NewMessage()
|
||||
//
|
||||
//emailBody := utils.BuildEmail()
|
||||
//m.SetHeader("From", "kotomi.poro1@gmail.com")
|
||||
//m.SetHeader("To", "nhocdl.poro1@gmail.com")
|
||||
//m.SetHeader("Subject", "Hello!")
|
||||
//m.SetBody("text/html", emailBody)
|
||||
//
|
||||
//d := mail.NewDialer("smtp.gmail.com", 587, "kotomi.poro1@gmail.com", "btmpjudzebyspfxw")
|
||||
//d.StartTLSPolicy = mail.MandatoryStartTLS
|
||||
//
|
||||
//// Send the email to Bob, Cora and Dan.
|
||||
//if err := d.DialAndSend(m); err != nil {
|
||||
// panic(err)
|
||||
//}
|
||||
|
||||
serect := os.Getenv("EMAIL_VERIFY_SECRET")
|
||||
//isPass, _ := generatorOtp("hello", "nhocdl.poro1@gmail.com", 12, serect)
|
||||
//fmt.Println(isPass)
|
||||
cipherBase64 := createLinkVerify(&models.CreateUser{
|
||||
Username: "thewind121212",
|
||||
Email: "nhocdl.poro1@gmail.com",
|
||||
Password: "linhporoQ1@",
|
||||
ConfirmPassword: "linhporoQ1@",
|
||||
}, serect)
|
||||
|
||||
key := []byte(serect)
|
||||
|
||||
i, err := decrypt(cipherBase64, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(i))
|
||||
|
||||
}
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
var registerInfo models.CreateUser
|
||||
|
||||
_ = json.NewDecoder(r.Body).Decode(®isterInfo)
|
||||
//call function check info user type in
|
||||
validRegisterInfo := checkAndValidDataFiled(®isterInfo, w)
|
||||
//call function check data user use in past or not
|
||||
isValidData := checkAccountExist(client, registerInfo.Username, registerInfo.Email, w)
|
||||
|
||||
if isValidData == false || validRegisterInfo == false {
|
||||
return errors.New("USER DON'T HAVE VALID INFO FOR REGISTER ACCOUNT")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *APIServer) handleAccount(w http.ResponseWriter, r *http.Request) error {
|
||||
if r.Method == http.MethodGet {
|
||||
ctx := context.Background()
|
||||
|
||||
res, err := utils.Redis.Ping(ctx).Result()
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
fmt.Println(res)
|
||||
|
||||
}
|
||||
if r.Method == http.MethodPost {
|
||||
fmt.Println("POST")
|
||||
}
|
||||
if r.Method == http.MethodDelete {
|
||||
fmt.Println("DELETE")
|
||||
}
|
||||
if r.Method == http.MethodPut {
|
||||
fmt.Println("PUT")
|
||||
}
|
||||
if r.Method == http.MethodPatch {
|
||||
fmt.Println("PATCH")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//register group-func
|
||||
|
||||
//checking is user create that have account before
|
||||
|
||||
func checkAndValidDataFiled(registerData *models.CreateUser, w http.ResponseWriter) bool {
|
||||
_ = models.Validate.RegisterValidation("customPassword", models.PasswordValidator)
|
||||
errs := models.Validate.Struct(registerData)
|
||||
var errStack []string
|
||||
if errs != nil {
|
||||
for _, err := range errs.(validator.ValidationErrors) {
|
||||
switch err.Field() {
|
||||
case "Email":
|
||||
{
|
||||
fmt.Println("Email không hợp lệ")
|
||||
errStack = append(errStack, "Email")
|
||||
}
|
||||
case "Username":
|
||||
{
|
||||
fmt.Println("User không hợp lệ")
|
||||
errStack = append(errStack, "User")
|
||||
}
|
||||
case "Password":
|
||||
{
|
||||
fmt.Println("Password không hợp lệ")
|
||||
errStack = append(errStack, "Password")
|
||||
}
|
||||
case "ConfirmPassword":
|
||||
{
|
||||
fmt.Println("Nhập lại mật khẩu sai")
|
||||
errStack = append(errStack, "ConfirmPassword")
|
||||
}
|
||||
case "PhoneNumber":
|
||||
{
|
||||
fmt.Println("SĐT không hợp lệ")
|
||||
errStack = append(errStack, "PhoneNumber")
|
||||
}
|
||||
}
|
||||
}
|
||||
//handle repose error
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
err := json.NewEncoder(w).Encode(errStack)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("There is error in write reponse at checking info user")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
func checkAccountExist(mongoClient *mongo.Client, userName string, email string, w http.ResponseWriter) bool {
|
||||
//filter in mongodb
|
||||
var isValid bool
|
||||
|
||||
filter := bson.D{
|
||||
{"$or", bson.A{
|
||||
bson.D{{"username", userName}},
|
||||
bson.D{{"email", email}},
|
||||
}},
|
||||
}
|
||||
|
||||
userData := mongoClient.Database("Totoday-shop").Collection("users")
|
||||
|
||||
var result models.UsersMongo
|
||||
err := userData.FindOne(context.TODO(), filter).Decode(&result)
|
||||
if err != nil {
|
||||
isValid = true
|
||||
}
|
||||
if err == nil {
|
||||
fmt.Println("Email or username already had register")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
err := json.NewEncoder(w).Encode("Your username or email had been register before")
|
||||
if err != nil {
|
||||
fmt.Println("There is error in write reponse at checking data user register")
|
||||
}
|
||||
isValid = false
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
|
||||
//after cheking register data generate otp and send email write valid time to confirm in redis
|
||||
// noice this will do concurency for speed reason
|
||||
|
||||
type otpGenerate struct {
|
||||
pureOTP string
|
||||
hashOTP string
|
||||
}
|
||||
|
||||
func generatorOtp(userName string, email string, counter uint64, serect string) (bool, *otpGenerate) {
|
||||
|
||||
serectBase32 := base32.StdEncoding.EncodeToString([]byte(serect + userName + email))
|
||||
passCode, err := hotp.GenerateCodeCustom(serectBase32, counter, hotp.ValidateOpts{
|
||||
Digits: 6,
|
||||
Algorithm: otp.AlgorithmSHA256,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Fail to create OTP")
|
||||
return false, &otpGenerate{
|
||||
pureOTP: "none",
|
||||
hashOTP: "none",
|
||||
}
|
||||
}
|
||||
|
||||
hashed, err := bcrypt.GenerateFromPassword([]byte(passCode), 5)
|
||||
if err != nil {
|
||||
fmt.Println("Fail to create OTP")
|
||||
return false, &otpGenerate{
|
||||
pureOTP: "none",
|
||||
hashOTP: "none",
|
||||
}
|
||||
}
|
||||
|
||||
return true, &otpGenerate{
|
||||
pureOTP: passCode,
|
||||
hashOTP: string(hashed),
|
||||
}
|
||||
}
|
||||
|
||||
func createLinkVerify(registerInfo *models.CreateUser, secrect string) string {
|
||||
|
||||
data, _ := json.Marshal(registerInfo)
|
||||
key := []byte(secrect)
|
||||
|
||||
ciphertext, _ := encrypt(data, key)
|
||||
|
||||
cipherTextBase64 := base64.StdEncoding.EncodeToString(ciphertext)
|
||||
|
||||
return cipherTextBase64
|
||||
}
|
||||
|
||||
func encrypt(data []byte, key []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Generate a random IV (Initialization Vector)
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
if _, err := rand.Read(iv); err != nil {
|
||||
fmt.Println("error generating IV:", err)
|
||||
}
|
||||
|
||||
// Pad the data to a multiple of the block size
|
||||
data = pkcs7Pad(data, aes.BlockSize)
|
||||
|
||||
// Create a CBC mode cipher block
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
|
||||
// Encrypt the data
|
||||
ciphertext := make([]byte, len(data))
|
||||
mode.CryptBlocks(ciphertext, data)
|
||||
|
||||
// Prepend the IV to the ciphertext
|
||||
ciphertext = append(iv, ciphertext...)
|
||||
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
func decrypt(base64Ciphertext string, key []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Decode base64
|
||||
ciphertext, err := base64.StdEncoding.DecodeString(base64Ciphertext)
|
||||
if err != nil {
|
||||
fmt.Println("error decoding base64:", err)
|
||||
}
|
||||
|
||||
// Extract the IV from the ciphertext
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
ciphertext = ciphertext[aes.BlockSize:]
|
||||
|
||||
// Create a CBC mode cipher block
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
|
||||
// Decrypt the data
|
||||
mode.CryptBlocks(ciphertext, ciphertext)
|
||||
|
||||
// Remove padding
|
||||
ciphertext = pkcs7Unpad(ciphertext)
|
||||
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
// pkcs7Pad pads the input to a multiple of blockSize using PKCS#7 padding
|
||||
func pkcs7Pad(data []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(data)%blockSize
|
||||
padText := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(data, padText...)
|
||||
}
|
||||
|
||||
// pkcs7Unpad removes PKCS#7 padding from the input
|
||||
func pkcs7Unpad(data []byte) []byte {
|
||||
padding := int(data[len(data)-1])
|
||||
return data[:len(data)-padding]
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"linhdevtran99/rest-api/models"
|
||||
)
|
||||
|
||||
func BuildEmail() string {
|
||||
|
||||
data := models.EmailTemplate{
|
||||
Otp: "11017",
|
||||
AlternativeLink: "https://www.google.com.vn",
|
||||
}
|
||||
|
||||
tmpl, err := template.ParseFiles("./Template/email.html")
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Cant achieve file")
|
||||
}
|
||||
|
||||
var result bytes.Buffer
|
||||
_ = tmpl.Execute(&result, data)
|
||||
|
||||
fmt.Println(result.String())
|
||||
return result.String()
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"go.mongodb.org/mongo-driver/mongo/readpref"
|
||||
)
|
||||
|
||||
var MongoDB *mongo.Client
|
||||
|
||||
func InitMongoDriver(mongoUri string) *mongo.Client {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
client, err := mongo.Connect(ctx, options.Client().ApplyURI(mongoUri))
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = client.Ping(ctx, readpref.Primary())
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
fmt.Println("MongoDB is ready")
|
||||
}
|
||||
|
||||
MongoDB = client
|
||||
|
||||
return client
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
var Redis *redis.Client
|
||||
|
||||
func RedisClientDriver(redisUri string) *redis.Client {
|
||||
ctx := context.Background()
|
||||
opt, err := redis.ParseURL(redisUri)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
redisClient := redis.NewClient(opt)
|
||||
res, err := redisClient.Ping(ctx).Result()
|
||||
|
||||
if err != nil {
|
||||
ctx.Done()
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if res == "PONG" {
|
||||
fmt.Println("Redis is ready")
|
||||
}
|
||||
|
||||
Redis = redisClient
|
||||
return redisClient
|
||||
}
|
||||
Loading…
Reference in New Issue