Compare commits
171 Commits
a0dd2583d6
...
f9a146321c
| Author | SHA1 | Date | |
|---|---|---|---|
| e37a974d9c | |||
| 470591cb44 | |||
| 38114769b3 | |||
| b05473a1c6 | |||
| 0fff694e8a | |||
| d8713298c4 | |||
| 763b0fc4bd | |||
| d8e18d7ffc | |||
| 381f1edb80 | |||
| a8e448b8ca | |||
| 9b0e3a5d5b | |||
| 5757a81cb8 | |||
| c4b8e630dc | |||
| 43b0242652 | |||
| 893744a1ab | |||
| 192cc569b4 | |||
| 56e6608537 | |||
| 0053033e32 | |||
| d1ff6a56fc | |||
| 114461c51d | |||
| 117a3e5d90 | |||
| fafc463f2a | |||
| e2bec481f0 | |||
| 89e7d35b5a | |||
| fe662c5355 | |||
| 6767a37704 | |||
| 2ea035a43b | |||
| 2a1ad499ed | |||
| 5cc6ddc8f1 | |||
| 0e070221f8 | |||
| 1ba32aa4c9 | |||
| edb3e07329 | |||
| f5304fae80 | |||
| d9be04541b | |||
| d2e06961b9 | |||
| 28092fcf17 | |||
| a7a20aebcf | |||
| c43c10982c | |||
| 02c4f9e3d1 | |||
| 1db22730aa | |||
| 184675a9b7 | |||
| 197ee7127b | |||
| 869fa48d74 | |||
| 7470f8e001 | |||
| fc70a9482c | |||
| e3afb58634 | |||
| bafb67dabc | |||
| 9ccd97564a | |||
| 08cb989975 | |||
| 455011fd99 | |||
| 4958cb0b93 | |||
| e8832f329a | |||
| 9c14480be7 | |||
| daf3e3f027 | |||
| a8df7d54bd | |||
| 2de82b9d2a | |||
| 00c2d6e205 | |||
| 87d922c558 | |||
| 0be7adefe3 | |||
| 3a9f81f1cb | |||
| 39e1b925e5 | |||
| a97b9f0983 | |||
| 42b4ade782 | |||
| 9edea29983 | |||
| c7f073c779 | |||
| 8e908982a8 | |||
| 8126406e5f | |||
| 6b68d918ba | |||
| fb5db25dce | |||
| f79e922fa0 | |||
| 3216e2620a | |||
| d796958d5e | |||
| f66904d428 | |||
| 22ec115b35 | |||
| 8d70777269 | |||
| 15ead6b0bc | |||
| 5abb3fd2b7 | |||
| 97636ce31d | |||
| ed85918e7f | |||
| c5ec99d3e1 | |||
| 2b4becdb61 | |||
| 4af93b3d7e | |||
| 429bbd1e7a | |||
| afc3a10f51 | |||
| 1c397da77a | |||
| 3834ca2e37 | |||
| 0898213aa8 | |||
| 5502c4d744 | |||
| cb08ecb53a | |||
| cb793092e9 | |||
| 70d775e0fc | |||
| 13f6492e5f | |||
| 92c5bf5b46 | |||
| f739eb3a8b | |||
| 6eed2be7f4 | |||
| c95d7747cd | |||
| 31782578f4 | |||
| 841dad4992 | |||
| 265ae0ac8b | |||
| ff7d56152e | |||
| cd126d2c59 | |||
| 2acca6dbe8 | |||
| d3332f530f | |||
| 484db90037 | |||
| b06eb86578 | |||
| 9704decb7a | |||
| 767d6bf002 | |||
| 79e00de9f6 | |||
| 1f7421dd2e | |||
| 7e5da4948c | |||
| 53701d61f8 | |||
| 6d02eb092c | |||
| 21d4080baa | |||
| 7bee78a875 | |||
| 2cd2a20065 | |||
| 74c0a215ed | |||
| e65fbafd36 | |||
| f0f5011e10 | |||
| 4ae86f0a57 | |||
| a55a435811 | |||
| 718c54f796 | |||
| 1b90e12fec | |||
| 9fd2316eeb | |||
| 3c9b959ad6 | |||
| 879d4b7092 | |||
| 562da693f1 | |||
| 7cd5211779 | |||
| 2399f8cd27 | |||
| b554a8783b | |||
| 37080b80f2 | |||
| 04c8f0094b | |||
| a034ea5ceb | |||
| c47353565b | |||
| 7d4d4049e8 | |||
| 6db196df28 | |||
| 8d9b975234 | |||
| efcc847405 | |||
| 4f6f9bf531 | |||
| 140da79f7f | |||
| 09328575ad | |||
| 4bb25a1eff | |||
| 91790330d2 | |||
| 40a5b4e878 | |||
| 50536caa00 | |||
| bf12ba76b6 | |||
| 84ab8949ec | |||
| f4582299aa | |||
| cbb95c6219 | |||
| ee20e5508e | |||
| 0ea219c721 | |||
| 19729c0809 | |||
| 6d63cce6d0 | |||
| 13021c47ce | |||
| 0a8f690714 | |||
| be7e5774ae | |||
| 7100199a17 | |||
| 8c75bbaf4a | |||
| d8aeec0fde | |||
| 6d529b4b8b | |||
| 30c1671e46 | |||
| b825b0c98e | |||
| b8f5d71be1 | |||
| 5696f177e2 | |||
| 621fd880a2 | |||
| 760e0bca28 | |||
| 4c59f33c70 | |||
| 41387ba902 | |||
| 827abf34fe | |||
| 4347909aab | |||
| 594b9fb700 | |||
| d38299b90d |
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,4 +1,10 @@
|
||||
.vscode/
|
||||
__debug_bin.exe
|
||||
*.log
|
||||
*.exe
|
||||
console/
|
||||
static/
|
||||
config.json
|
||||
*-firebase-*.json
|
||||
maingate.zip
|
||||
maingate.sh
|
||||
maingate
|
||||
|
||||
37
backup/firebase-jssdk/fb-ga.js
Normal file
37
backup/firebase-jssdk/fb-ga.js
Normal file
@ -0,0 +1,37 @@
|
||||
// Import the functions you need from the SDKs you need
|
||||
import { initializeApp } from './firebase-app.js';
|
||||
import { getAnalytics, logEvent } from './firebase-analytics.js';
|
||||
|
||||
// TODO: Add SDKs for Firebase products that you want to use
|
||||
// https://firebase.google.com/docs/web/setup#available-libraries
|
||||
|
||||
// Your web app's Firebase configuration
|
||||
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
|
||||
const firebaseConfig = {
|
||||
apiKey: "{{.FBA_apiKey}}",
|
||||
authDomain: "{{.FBA_authDomain}}",
|
||||
databaseURL: "{{.FBA_databaseURL}}",
|
||||
projectId: "{{.FBA_projectId}}",
|
||||
storageBucket: "{{.FBA_storageBucket}}",
|
||||
messagingSenderId: "{{.FBA_messagingSenderId}}",
|
||||
appId: "{{.FBA_appId}}",
|
||||
measurementId: "{{.FBA_measurementId}}"
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Initialize Firebase
|
||||
const app = initializeApp(firebaseConfig);
|
||||
const analytics = getAnalytics(app);
|
||||
|
||||
// LogEvent('DESKTOP_TEST8');
|
||||
|
||||
export function LogEvent(args){
|
||||
|
||||
if ( arguments.length == 1) {
|
||||
logEvent(analytics, arguments[0]);
|
||||
} else {
|
||||
logEvent(analytics, arguments[0], arguments[1]);
|
||||
}
|
||||
|
||||
}
|
||||
1
backup/firebase-jssdk/fb-ga.min.js
vendored
Normal file
1
backup/firebase-jssdk/fb-ga.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2376
backup/firebase-jssdk/fb-ga.rollup.js
Normal file
2376
backup/firebase-jssdk/fb-ga.rollup.js
Normal file
File diff suppressed because one or more lines are too long
3
backup/firebase-jssdk/firebase-analytics.js
Normal file
3
backup/firebase-jssdk/firebase-analytics.js
Normal file
File diff suppressed because one or more lines are too long
2522
backup/firebase-jssdk/firebase-app.js
Normal file
2522
backup/firebase-jssdk/firebase-app.js
Normal file
File diff suppressed because it is too large
Load Diff
537
backup/firebase-jssdk/js.js
Normal file
537
backup/firebase-jssdk/js.js
Normal file
File diff suppressed because one or more lines are too long
3
backup/firebase-jssdk/original/firebase-analytics.js
Normal file
3
backup/firebase-jssdk/original/firebase-analytics.js
Normal file
File diff suppressed because one or more lines are too long
2522
backup/firebase-jssdk/original/firebase-app.js
Normal file
2522
backup/firebase-jssdk/original/firebase-app.js
Normal file
File diff suppressed because it is too large
Load Diff
64
config.json
64
config.json
@ -1,64 +0,0 @@
|
||||
{
|
||||
"region_storage" : {
|
||||
"private" : {
|
||||
"mongo" : "mongodb://192.168.8.94:27017/?replicaSet=repl01&retrywrites=false",
|
||||
"redis" : {
|
||||
"url" : "redis://192.168.8.94:6379",
|
||||
"offset" : {
|
||||
"cache" : 0,
|
||||
"session" : 1,
|
||||
"ranking" : 2,
|
||||
"chat" : 3
|
||||
}
|
||||
}
|
||||
},
|
||||
"dev" : {
|
||||
"mongo" : "mongodb://192.168.8.94:27017/?replicaSet=repl01&retrywrites=false",
|
||||
"redis" : {
|
||||
"url" : "redis://192.168.8.94:6379",
|
||||
"offset" : {
|
||||
"cache" : 0,
|
||||
"session" : 1,
|
||||
"ranking" : 2,
|
||||
"chat" : 3
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"maingate_mongodb_url" : "mongodb://192.168.8.94:27017/?replicaSet=repl01&retrywrites=false",
|
||||
"maingate_service_url" : "http://localhost/maingate",
|
||||
"maingate_global_admins" : [
|
||||
"rehjinh@action2quare.com"
|
||||
],
|
||||
"tavern_service_url" : "http://localhost/tavern",
|
||||
"port" : 8080,
|
||||
|
||||
"postoffice_mongodb_url" : "mongodb://192.168.8.94:27017/?replicaSet=repl01&retrywrites=false",
|
||||
"postoffice_service_url" : "http://localhost/maingate",
|
||||
|
||||
"autologin_ttl": 604800,
|
||||
"redirect_base_url": "https://auth.action2quare.com",
|
||||
"google_client_id" : "46698421246-fv2k7chr1j95ju1vm10ogq8prkjt8272.apps.googleusercontent.com",
|
||||
"google_client_secret" : "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",
|
||||
|
||||
"twitter_oauth_key": "1045586021293862912-MSaciEnwsyNvgfjtmIjGTLA882X8DG",
|
||||
"twitter_oauth_secret": "eclZpTlRQM3igThV7rVoVM5WnyJq9Eu9KfB2bWqvCIzUX",
|
||||
"twitter_customer_key": "mZTsefCkkiwa3Qgj2WYbAGdS5",
|
||||
"twitter_customer_secret": "300zHEJu17JuFupvigdi5s1B5nSiEAO1JqtcX9ZDMnUBJ8Bn6q",
|
||||
|
||||
"apple_client_id": "auth.service.action2quare.com",
|
||||
"apple_privatekey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgi3HkbNY93XdcNJVa\nAzR895cHxPXYeT0HnAOCzW5IOlOgCgYIKoZIzj0DAQehRANCAAS81nJzJcsZWtdr\n7sAeyqyHFoyCBdmsqI3fvLWYj/5M3MqgMI7pYyVbSmtXT9El/67Y4vz2e/9gllLy\ns0S/XoFo\n-----END PRIVATE KEY-----",
|
||||
"apple_service_id": "auth.service.action2quare.com",
|
||||
"apple_team_id": "YC94S4Z6CS",
|
||||
"apple_key_id": "47UBTLARC8",
|
||||
|
||||
"microsoft_client_id": "ebc03204-a5b4-41bf-ac2b-5051615ccf33",
|
||||
"microsoft_client_secret" : "fa78Q~9C4zEadeOf5ACSFsenP35jHVLKdW.jvcNr",
|
||||
|
||||
"gamepot_project_id": "dbfe1334-6dde-43e0-b8a9-cc0733d4c60e",
|
||||
"gamepot_logincheckapi_url": "https://gamepot.apigw.ntruss.com/gpapps/v1/loginauth",
|
||||
|
||||
"firebase_admin_sdk_credentialfile": "kingdom-2b812-firebase-adminsdk-a6j68-d42ae01182.json"
|
||||
|
||||
}
|
||||
@ -1 +1,41 @@
|
||||
{}
|
||||
{
|
||||
"maingate_mongodb_url": "mongodb://...",
|
||||
"autologin_ttl": 604800,
|
||||
"acc_del_ttl": 7776000,
|
||||
"maximum_num_link_account": 10,
|
||||
"redirect_base_url": "",
|
||||
"google_client_id" : "",
|
||||
"google_client_secret" : "",
|
||||
|
||||
"twitter_oauth_key": "",
|
||||
"twitter_oauth_secret": "",
|
||||
"twitter_customer_key": "",
|
||||
"twitter_customer_secret": "",
|
||||
|
||||
"apple_client_id": "",
|
||||
"apple_privatekey": "",
|
||||
"apple_service_id": "",
|
||||
"apple_team_id": "",
|
||||
"apple_key_id": "",
|
||||
|
||||
"microsoft_client_id": "",
|
||||
"microsoft_client_secret" : "",
|
||||
|
||||
"gamepot_project_id": "",
|
||||
"gamepot_logincheckapi_url": "",
|
||||
|
||||
"firebase_admin_sdk_credentialfile": "",
|
||||
|
||||
"firebase_google_analytics_jssdk_apikey": "",
|
||||
"firebase_google_analytics_jssdk_authdomain": "",
|
||||
"firebase_google_analytics_jssdk_databaseurl": "",
|
||||
"firebase_google_analytics_jssdk_projectid": "",
|
||||
"firebase_google_analytics_jssdk_storagebucket": "",
|
||||
"firebase_google_analytics_jssdk_messagingsenderid": "",
|
||||
"firebase_google_analytics_jssdk_apiid": "",
|
||||
"firebase_google_analytics_jssdk_measurementid": "",
|
||||
|
||||
"maingate_global_admins" : [
|
||||
"mountain@action2quare.com"
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "https://auth.action2quare.com/console/static/css/main.57f4cd54.css",
|
||||
"main.js": "https://auth.action2quare.com/console/static/js/main.2ea4d7d1.js",
|
||||
"static/js/811.8f231000.chunk.js": "https://auth.action2quare.com/console/static/js/811.8f231000.chunk.js",
|
||||
"static/js/514.99ab97af.chunk.js": "https://auth.action2quare.com/console/static/js/514.99ab97af.chunk.js",
|
||||
"static/css/617.e367b0e1.chunk.css": "https://auth.action2quare.com/console/static/css/617.e367b0e1.chunk.css",
|
||||
"static/js/617.ef9b57b1.chunk.js": "https://auth.action2quare.com/console/static/js/617.ef9b57b1.chunk.js",
|
||||
"static/js/348.a88c7705.chunk.js": "https://auth.action2quare.com/console/static/js/348.a88c7705.chunk.js",
|
||||
"static/js/297.8ae1e5e0.chunk.js": "https://auth.action2quare.com/console/static/js/297.8ae1e5e0.chunk.js",
|
||||
"static/js/340.ce8215ad.chunk.js": "https://auth.action2quare.com/console/static/js/340.ce8215ad.chunk.js",
|
||||
"static/js/18.7ddf5096.chunk.js": "https://auth.action2quare.com/console/static/js/18.7ddf5096.chunk.js",
|
||||
"static/js/664.556c2c72.chunk.js": "https://auth.action2quare.com/console/static/js/664.556c2c72.chunk.js",
|
||||
"static/css/691.57000fb1.chunk.css": "https://auth.action2quare.com/console/static/css/691.57000fb1.chunk.css",
|
||||
"static/js/691.b7fcc27d.chunk.js": "https://auth.action2quare.com/console/static/js/691.b7fcc27d.chunk.js",
|
||||
"static/js/491.6101d763.chunk.js": "https://auth.action2quare.com/console/static/js/491.6101d763.chunk.js",
|
||||
"static/js/998.7113153c.chunk.js": "https://auth.action2quare.com/console/static/js/998.7113153c.chunk.js",
|
||||
"static/js/370.79fc8df3.chunk.js": "https://auth.action2quare.com/console/static/js/370.79fc8df3.chunk.js",
|
||||
"static/js/176.44035bcc.chunk.js": "https://auth.action2quare.com/console/static/js/176.44035bcc.chunk.js",
|
||||
"index.html": "https://auth.action2quare.com/console/index.html"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.57f4cd54.css",
|
||||
"static/js/main.2ea4d7d1.js"
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="https://auth.action2quare.com/console/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Maingate Console"/><link rel="apple-touch-icon" href="https://auth.action2quare.com/console/logo192.png"/><link rel="manifest" href="https://auth.action2quare.com/console/manifest.json"/><title>Maingate Console</title><script defer="defer" src="https://auth.action2quare.com/console/static/js/main.2ea4d7d1.js"></script><link href="https://auth.action2quare.com/console/static/css/main.57f4cd54.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB |
@ -1,25 +0,0 @@
|
||||
{
|
||||
"short_name": "Maingate Console",
|
||||
"name": "Maingate Console",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
@ -1 +0,0 @@
|
||||
[data-simplebar]{align-content:flex-start;align-items:flex-start;flex-direction:column;flex-wrap:wrap;justify-content:flex-start;position:relative}.simplebar-wrapper{height:inherit;max-height:inherit;max-width:inherit;overflow:hidden;width:inherit}.simplebar-mask{direction:inherit;height:auto!important;overflow:hidden;width:auto!important;z-index:0}.simplebar-mask,.simplebar-offset{bottom:0;left:0;margin:0;padding:0;position:absolute;right:0;top:0}.simplebar-offset{-webkit-overflow-scrolling:touch;box-sizing:inherit!important;direction:inherit!important;resize:none!important}.simplebar-content-wrapper{-ms-overflow-style:none;box-sizing:border-box!important;direction:inherit;display:block;height:100%;max-height:100%;max-width:100%;position:relative;scrollbar-width:none;width:auto}.simplebar-content-wrapper::-webkit-scrollbar,.simplebar-hide-scrollbar::-webkit-scrollbar{display:none;height:0;width:0}.simplebar-content:after,.simplebar-content:before{content:" ";display:table}.simplebar-placeholder{max-height:100%;max-width:100%;pointer-events:none;width:100%}.simplebar-height-auto-observer-wrapper{box-sizing:inherit!important;flex-basis:0;flex-grow:inherit;flex-shrink:0;float:left;height:100%;margin:0;max-height:1px;max-width:1px;overflow:hidden;padding:0;pointer-events:none;position:relative;width:100%;z-index:-1}.simplebar-height-auto-observer{box-sizing:inherit;display:block;height:1000%;left:0;min-height:1px;min-width:1px;opacity:0;top:0;width:1000%;z-index:-1}.simplebar-height-auto-observer,.simplebar-track{overflow:hidden;pointer-events:none;position:absolute}.simplebar-track{bottom:0;right:0;z-index:1}[data-simplebar].simplebar-dragging .simplebar-content{pointer-events:none;user-select:none;-webkit-user-select:none}[data-simplebar].simplebar-dragging .simplebar-track{pointer-events:all}.simplebar-scrollbar{left:0;min-height:10px;position:absolute;right:0}.simplebar-scrollbar:before{background:#000;border-radius:7px;content:"";left:2px;opacity:0;position:absolute;right:2px;transition:opacity .2s linear}.simplebar-scrollbar.simplebar-visible:before{opacity:.5;transition:opacity 0s linear}.simplebar-track.simplebar-vertical{top:0;width:11px}.simplebar-track.simplebar-vertical .simplebar-scrollbar:before{bottom:2px;top:2px}.simplebar-track.simplebar-horizontal{height:11px;left:0}.simplebar-track.simplebar-horizontal .simplebar-scrollbar:before{height:100%;left:2px;right:2px}.simplebar-track.simplebar-horizontal .simplebar-scrollbar{height:7px;left:0;min-height:0;min-width:10px;right:auto;top:2px;width:auto}[data-simplebar-direction=rtl] .simplebar-track.simplebar-vertical{left:0;right:auto}.hs-dummy-scrollbar-size{direction:rtl;height:500px;opacity:0;overflow-x:scroll;overflow-y:hidden;position:fixed;visibility:hidden;width:500px}.simplebar-hide-scrollbar{-ms-overflow-style:none;left:0;overflow-y:scroll;position:fixed;scrollbar-width:none;visibility:hidden}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +0,0 @@
|
||||
/*! For license information please see 370.79fc8df3.chunk.js.LICENSE.txt */
|
||||
"use strict";(self.webpackChunkmaingate_console=self.webpackChunkmaingate_console||[]).push([[370],{22370:function(e,t,r){r.d(t,{Z:function(){return m}});var n=r(47313),o=function(){return o=Object.assign||function(e){for(var t,r=1,n=arguments.length;r<n;r++)for(var o in t=arguments[r])Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o]);return e},o.apply(this,arguments)};var s={exports:{}};var a,i,c,p;function l(){if(i)return a;i=1;return a="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"}s.exports=function(){if(p)return c;p=1;var e=l();function t(){}function r(){}return r.resetWarningCache=t,c=function(){function n(t,r,n,o,s,a){if(a!==e){var i=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw i.name="Invariant Violation",i}}function o(){return n}n.isRequired=n;var s={array:n,bigint:n,bool:n,func:n,number:n,object:n,string:n,symbol:n,any:n,arrayOf:o,element:n,elementType:n,instanceOf:o,node:n,objectOf:o,oneOf:o,oneOfType:o,shape:o,exact:o,checkPropTypes:r,resetWarningCache:t};return s.PropTypes=s,s}}()();var u,f={exports:{}};u=f,function(){var e={}.hasOwnProperty;function t(){for(var r=[],n=0;n<arguments.length;n++){var o=arguments[n];if(o){var s=typeof o;if("string"===s||"number"===s)r.push(o);else if(Array.isArray(o)){if(o.length){var a=t.apply(null,o);a&&r.push(a)}}else if("object"===s)if(o.toString===Object.prototype.toString)for(var i in o)e.call(o,i)&&o[i]&&r.push(i);else r.push(o.toString())}}return r.join(" ")}u.exports?(t.default=t,u.exports=t):window.classNames=t}();var y=f.exports,m=(0,n.forwardRef)((function(e,t){var r,s=e.className,a=e.content,i=e.customClassName,c=e.height,p=e.icon,l=e.name,u=e.size,f=e.title,m=e.use,g=e.width,h=function(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(null!=e&&"function"===typeof Object.getOwnPropertySymbols){var o=0;for(n=Object.getOwnPropertySymbols(e);o<n.length;o++)t.indexOf(n[o])<0&&Object.prototype.propertyIsEnumerable.call(e,n[o])&&(r[n[o]]=e[n[o]])}return r}(e,["className","content","customClassName","height","icon","name","size","title","use","width"]),x=(0,n.useState)(0),v=x[0],w=x[1],O=p||a||l;a&&process,l&&process,(0,n.useMemo)((function(){return w(v+1)}),[O,JSON.stringify(O)]);var b=(0,n.useMemo)((function(){return O&&"string"===typeof O&&O.includes("-")?O.replace(/([-_][a-z0-9])/gi,(function(e){return e.toUpperCase()})).replace(/-/gi,""):O}),[v]),d=f?"<title>".concat(f,"</title>"):"",T=(0,n.useMemo)((function(){return Array.isArray(O)?O:"string"===typeof O&&n.icons?n.icons[b]:void 0}),[v]),_=(0,n.useMemo)((function(){return Array.isArray(T)?T[1]||T[0]:T}),[v]),N=Array.isArray(T)&&T.length>1?T[0]:"64 64",S=h.viewBox||"0 0 ".concat(N),j=i?y(i):y("icon",((r={})["icon-".concat(u)]=u,r["icon-custom-size"]=c||g,r),s);return m?n.createElement("svg",o({xmlns:"http://www.w3.org/2000/svg",className:j},c&&{height:c},g&&{width:g},{role:"img"},h,{ref:t}),n.createElement("use",{href:m})):n.createElement("svg",o({xmlns:"http://www.w3.org/2000/svg",viewBox:S,className:j},c&&{height:c},g&&{width:g},{role:"img",dangerouslySetInnerHTML:{__html:d+_}},h,{ref:t}))}));m.propTypes={className:s.exports.string,content:s.exports.oneOfType([s.exports.array,s.exports.string]),customClassName:s.exports.string,height:s.exports.number,icon:s.exports.oneOfType([s.exports.array,s.exports.string]),name:s.exports.string,size:s.exports.oneOf(["custom","custom-size","sm","lg","xl","xxl","3xl","4xl","5xl","6xl","7xl","8xl","9xl"]),title:s.exports.any,use:s.exports.any,width:s.exports.number},m.displayName="CIcon"}}]);
|
||||
@ -1,14 +0,0 @@
|
||||
/*!
|
||||
Copyright (c) 2018 Jed Watson.
|
||||
Licensed under the MIT License (MIT), see
|
||||
http://jedwatson.github.io/classnames
|
||||
*/
|
||||
|
||||
/** @license React v16.13.1
|
||||
* react-is.development.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
"use strict";(self.webpackChunkmaingate_console=self.webpackChunkmaingate_console||[]).push([[514],{82514:function(e,s,l){l.r(s),l.d(s,{default:function(){return i}});l(47313);var c=l(27998),a=l(22370),n=["512 512","<path fill='var(--ci-primary-color, currentColor)' d='M479.6,399.716l-81.084-81.084-62.368-25.767A175.014,175.014,0,0,0,368,192c0-97.047-78.953-176-176-176S16,94.953,16,192,94.953,368,192,368a175.034,175.034,0,0,0,101.619-32.377l25.7,62.2L400.4,478.911a56,56,0,1,0,79.2-79.195ZM48,192c0-79.4,64.6-144,144-144s144,64.6,144,144S271.4,336,192,336,48,271.4,48,192ZM456.971,456.284a24.028,24.028,0,0,1-33.942,0l-76.572-76.572-23.894-57.835L380.4,345.771l76.573,76.572A24.028,24.028,0,0,1,456.971,456.284Z' class='ci-primary'/>"],r=l(46417);function i(){return(0,r.jsx)("div",{className:"bg-light min-vh-100 d-flex flex-row align-items-center",children:(0,r.jsx)(c.KB,{children:(0,r.jsx)(c.rb,{className:"justify-content-center",children:(0,r.jsxs)(c.b7,{md:6,children:[(0,r.jsxs)("div",{className:"clearfix",children:[(0,r.jsx)("h1",{className:"float-start display-3 me-4",children:"404"}),(0,r.jsx)("h4",{className:"pt-3",children:"not found."}),(0,r.jsx)("p",{className:"text-medium-emphasis float-start",children:"\ud574\ub2f9 \ud398\uc774\uc9c0\ub97c \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. \uad00\ub9ac\uc790\uc5d0\uac8c \ubb38\uc758\ud558\uc138\uc694."})]}),(0,r.jsxs)(c.YR,{className:"input-prepend",children:[(0,r.jsx)(c.wV,{children:(0,r.jsx)(a.Z,{icon:n})}),(0,r.jsx)(c.jO,{type:"text",placeholder:"\ubb34\uc5c7\uc744 \ucc3e\uc73c\uc2dc\ub098\uc694?"}),(0,r.jsx)(c.u5,{color:"info",children:"\ucc3e\uae30"})]})]})})})})}}}]);
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
||||
File diff suppressed because one or more lines are too long
@ -1,14 +0,0 @@
|
||||
/*!
|
||||
Copyright (c) 2018 Jed Watson.
|
||||
Licensed under the MIT License (MIT), see
|
||||
http://jedwatson.github.io/classnames
|
||||
*/
|
||||
|
||||
/** @license React v16.13.1
|
||||
* react-is.development.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
File diff suppressed because one or more lines are too long
@ -1,130 +0,0 @@
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
***************************************************************************** */
|
||||
|
||||
/*! @azure/msal-browser v2.31.0 2022-11-07 */
|
||||
|
||||
/*! @azure/msal-common v8.0.0 2022-11-07 */
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-dom.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-is.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-jsx-runtime.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* scheduler.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* use-sync-external-store-shim.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* use-sync-external-store-shim/with-selector.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @remix-run/router v1.0.3
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router DOM v6.4.3
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router v6.4.3
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/** @license React v16.13.1
|
||||
* react-is.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
611
core/api.go
611
core/api.go
@ -1,161 +1,245 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sort"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/common"
|
||||
"repositories.action2quare.com/ayo/go-ayo/logger"
|
||||
"repositories.action2quare.com/ayo/gocommon"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
func (caller apiCaller) isGlobalAdmin() bool {
|
||||
if *noauth {
|
||||
return true
|
||||
}
|
||||
|
||||
email, ok := caller.userinfo["email"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if _, ok := caller.admins[email.(string)]; ok {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
type FileDocumentDesc struct {
|
||||
Key string `bson:"key" json:"key"`
|
||||
Src string `bson:"src" json:"src"`
|
||||
Link string `bson:"link" json:"link"`
|
||||
Desc string `bson:"desc" json:"desc"`
|
||||
Extract bool `bson:"extract" json:"extract"`
|
||||
Timestamp int64 `bson:"timestamp" json:"timestamp"`
|
||||
Contents []byte `bson:"contents,omitempty" json:"contents,omitempty"`
|
||||
}
|
||||
|
||||
func (caller apiCaller) writeAccessableServices(w http.ResponseWriter) {
|
||||
services, editable := caller.getAccessableServices()
|
||||
for _, r := range editable {
|
||||
w.Header().Add("MG-X-SERVICE-EDITABLE", r)
|
||||
func (fd *FileDocumentDesc) Save() error {
|
||||
// 새 파일 올라옴
|
||||
if len(fd.Contents) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
w.Write([]byte("{"))
|
||||
start := true
|
||||
for _, v := range services {
|
||||
if !start {
|
||||
w.Write([]byte(","))
|
||||
}
|
||||
w.Write([]byte(fmt.Sprintf(`"%s":`, v.ServiceName)))
|
||||
serptr := atomic.LoadPointer(&v.serviceSerialized)
|
||||
w.Write(*(*[]byte)(serptr))
|
||||
start = false
|
||||
}
|
||||
w.Write([]byte("}"))
|
||||
}
|
||||
|
||||
func (caller apiCaller) getAccessableServices() ([]*serviceDescription, []string) {
|
||||
allservices := caller.mg.services.all()
|
||||
v, ok := caller.userinfo["email"]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
var destFile string
|
||||
if fd.Extract {
|
||||
os.MkdirAll(fd.Link, os.ModePerm)
|
||||
destFile = path.Join(fd.Link, fd.Src)
|
||||
} else {
|
||||
os.MkdirAll(path.Dir(fd.Link), os.ModePerm)
|
||||
destFile = fd.Link
|
||||
}
|
||||
|
||||
email := v.(string)
|
||||
_, admin := caller.admins[email]
|
||||
f, err := os.Create(destFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var output []*serviceDescription
|
||||
var editable []string
|
||||
for _, desc := range allservices {
|
||||
if admin {
|
||||
output = append(output, desc)
|
||||
editable = append(editable, desc.ServiceName)
|
||||
} else if desc.isValidAPIUser("*", email) {
|
||||
output = append(output, desc)
|
||||
if desc.isValidAPIUser("service", email) {
|
||||
editable = append(editable, desc.ServiceName)
|
||||
}
|
||||
_, err = io.Copy(f, bytes.NewBuffer(fd.Contents))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fd.Extract {
|
||||
switch path.Ext(destFile) {
|
||||
case ".zip":
|
||||
err = gocommon.Unzip(destFile)
|
||||
case ".tar":
|
||||
err = gocommon.Untar(destFile)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(output, func(i, j int) bool {
|
||||
return output[i].ServiceName < output[j].ServiceName
|
||||
})
|
||||
|
||||
return output, editable
|
||||
return err
|
||||
}
|
||||
|
||||
func (caller apiCaller) isValidUser(service any, category string) (valid bool, admin bool) {
|
||||
if *noauth {
|
||||
return true, true
|
||||
}
|
||||
|
||||
v, ok := caller.userinfo["email"]
|
||||
if !ok {
|
||||
logger.Println("isVaidUser failed. email is missing :", caller.userinfo)
|
||||
return false, false
|
||||
}
|
||||
|
||||
email := v.(string)
|
||||
if _, ok := caller.admins[email]; ok {
|
||||
return true, true
|
||||
}
|
||||
|
||||
svcdesc := caller.mg.services.get(service)
|
||||
if svcdesc == nil {
|
||||
logger.Println("isVaidUser failed. service is missing :", service)
|
||||
return false, false
|
||||
}
|
||||
|
||||
return svcdesc.isValidAPIUser(category, email), false
|
||||
}
|
||||
|
||||
func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
mg := caller.mg
|
||||
queryvals := r.URL.Query()
|
||||
func (caller apiCaller) filesAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
if r.Method == "GET" {
|
||||
service := queryvals.Get("service")
|
||||
allfiles, err := caller.mg.mongoClient.All(CollectionFile, options.Find().SetProjection(bson.M{
|
||||
"contents": 0,
|
||||
}).SetReturnKey(false))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if valid, _ := caller.isValidUser(service, "whitelist"); !valid {
|
||||
logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
if len(allfiles) > 0 {
|
||||
enc := json.NewEncoder(w)
|
||||
return enc.Encode(allfiles)
|
||||
}
|
||||
} else if r.Method == "DELETE" {
|
||||
key := r.FormValue("key")
|
||||
if len(key) == 0 {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(service) > 0 {
|
||||
_, err := caller.mg.mongoClient.Delete(CollectionFile, bson.M{
|
||||
"key": key,
|
||||
})
|
||||
|
||||
all, err := mg.mongoClient.FindAll(CollectionWhitelist, bson.M{
|
||||
"service": service,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(all) > 0 {
|
||||
allraw, _ := json.Marshal(all)
|
||||
w.Write(allraw)
|
||||
}
|
||||
} else {
|
||||
logger.Println("service param is missing")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var seq = uint32(0)
|
||||
|
||||
func (caller apiCaller) uploadAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
if r.Method == "PUT" {
|
||||
infile, header, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return err
|
||||
}
|
||||
defer infile.Close()
|
||||
|
||||
desc := r.FormValue("desc")
|
||||
contents, _ := io.ReadAll(infile)
|
||||
extractstr := r.FormValue("extract")
|
||||
extract, _ := strconv.ParseBool(extractstr)
|
||||
|
||||
var b [5]byte
|
||||
binary.BigEndian.PutUint32(b[0:4], uint32(time.Now().Unix()))
|
||||
b[4] = byte(atomic.AddUint32(&seq, 1) % 255)
|
||||
|
||||
newidobj := primitive.NewObjectID()
|
||||
copy(newidobj[:], b[1:])
|
||||
|
||||
rf := newidobj.Hex()
|
||||
var link string
|
||||
if extract {
|
||||
link = path.Join("static", rf)
|
||||
} else {
|
||||
link = path.Join("static", rf, header.Filename)
|
||||
}
|
||||
|
||||
newdoc := FileDocumentDesc{
|
||||
Contents: contents,
|
||||
Src: header.Filename,
|
||||
Timestamp: time.Now().UTC().Unix(),
|
||||
Extract: extract,
|
||||
Link: link,
|
||||
Desc: desc,
|
||||
Key: rf,
|
||||
}
|
||||
_, _, err = caller.mg.mongoClient.UpsertOne(CollectionFile, bson.M{
|
||||
"_id": newidobj,
|
||||
"key": rf,
|
||||
}, newdoc)
|
||||
|
||||
if err == nil {
|
||||
newdoc.Contents = nil
|
||||
enc := json.NewEncoder(w)
|
||||
enc.Encode(newdoc)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (caller apiCaller) blockAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
mg := caller.mg
|
||||
if r.Method == "GET" {
|
||||
target, ok := gocommon.ReadObjectIDFormValue(r.Form, "accid")
|
||||
if ok {
|
||||
json.NewEncoder(w).Encode(mg.bl.all())
|
||||
} else if !target.IsZero() {
|
||||
if blocked, ok := mg.bl.get(target); ok && blocked != nil {
|
||||
json.NewEncoder(w).Encode(blocked)
|
||||
}
|
||||
}
|
||||
} else if r.Method == "PUT" {
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
|
||||
var bipl blockinfoWithStringId
|
||||
if err := json.Unmarshal(body, &bipl); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accid, err := primitive.ObjectIDFromHex(bipl.StrId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bi := blockinfo{
|
||||
Start: primitive.NewDateTimeFromTime(time.Unix(bipl.StartUnix, 0)),
|
||||
End: primitive.NewDateTimeFromTime(time.Unix(bipl.EndUnix, 0)),
|
||||
Reason: bipl.Reason,
|
||||
}
|
||||
|
||||
logger.Println("bi :", accid, bi)
|
||||
|
||||
_, _, err = mg.mongoClient.Update(CollectionBlock, bson.M{
|
||||
"_id": accid,
|
||||
}, bson.M{
|
||||
"$set": &bi,
|
||||
}, options.Update().SetUpsert(true))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if r.Method == "DELETE" {
|
||||
id := r.URL.Query().Get("id")
|
||||
|
||||
if len(id) == 0 {
|
||||
return errors.New("id param is missing")
|
||||
}
|
||||
idobj, err := primitive.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, _, err = mg.mongoClient.Update(CollectionBlock, bson.M{
|
||||
"_id": idobj,
|
||||
}, bson.M{
|
||||
"$currentDate": bson.M{
|
||||
"_ts": bson.M{"$type": "date"},
|
||||
},
|
||||
}, options.Update().SetUpsert(false))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mg.mongoClient.Delete(CollectionAuth, bson.M{"_id": idobj})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
mg := caller.mg
|
||||
if r.Method == "GET" {
|
||||
enc := json.NewEncoder(w)
|
||||
enc.Encode(mg.wl.all())
|
||||
} else if r.Method == "PUT" {
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
var member whitelistmember
|
||||
if err := json.Unmarshal(body, &member); err != nil {
|
||||
return err
|
||||
}
|
||||
if valid, _ := caller.isValidUser(member.Service, "whitelist"); !valid {
|
||||
logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return nil
|
||||
}
|
||||
|
||||
member.Expired = 0
|
||||
|
||||
member.ExpiredAt = 0
|
||||
member.Id = primitive.NilObjectID
|
||||
_, _, err := mg.mongoClient.Update(CollectionWhitelist, bson.M{
|
||||
"_id": primitive.NewObjectID(),
|
||||
}, bson.M{
|
||||
@ -166,7 +250,8 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
|
||||
return err
|
||||
}
|
||||
} else if r.Method == "DELETE" {
|
||||
id := queryvals.Get("id")
|
||||
id := r.URL.Query().Get("id")
|
||||
|
||||
if len(id) == 0 {
|
||||
return errors.New("id param is missing")
|
||||
}
|
||||
@ -191,25 +276,23 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
|
||||
|
||||
func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
mg := caller.mg
|
||||
queryvals := r.URL.Query()
|
||||
if r.Method == "GET" {
|
||||
name := queryvals.Get("name")
|
||||
if len(name) > 0 {
|
||||
if valid, _ := caller.isValidUser(name, "*"); !valid {
|
||||
logger.Println("serviceAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return nil
|
||||
logger.Println("serviceAPI :", r.URL.Path)
|
||||
if mg.service().Id.IsZero() {
|
||||
logger.Println(" id is zero")
|
||||
newService := serviceDescription{
|
||||
ServiceDescriptionSummary: ServiceDescriptionSummary{
|
||||
Id: primitive.NewObjectID(),
|
||||
},
|
||||
}
|
||||
|
||||
if valid, admin := caller.isValidUser(name, "service"); valid || admin {
|
||||
w.Header().Add("MG-X-SERVICE-EDITABLE", name)
|
||||
if err := newService.prepare(caller.mg); err != nil {
|
||||
logger.Println(" prepare failed :", err)
|
||||
return err
|
||||
}
|
||||
|
||||
serptr := atomic.LoadPointer(&mg.services.get(name).serviceSerialized)
|
||||
w.Write(*(*[]byte)(serptr))
|
||||
} else {
|
||||
caller.writeAccessableServices(w)
|
||||
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(&newService))
|
||||
}
|
||||
|
||||
w.Write(mg.service().serviceSerialized)
|
||||
} else if r.Method == "POST" {
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
var service serviceDescription
|
||||
@ -217,18 +300,10 @@ func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error
|
||||
return err
|
||||
}
|
||||
|
||||
if service.Id.IsZero() {
|
||||
if caller.isGlobalAdmin() {
|
||||
service.Id = primitive.NewObjectID()
|
||||
} else {
|
||||
logger.Println("serviceAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return nil
|
||||
if len(service.ServerApiTokens) == 0 {
|
||||
service.ServerApiTokens = []primitive.ObjectID{
|
||||
primitive.NewObjectIDFromTimestamp(time.Now().Add(-time.Hour * 24 * 30 * 465)),
|
||||
}
|
||||
} else if valid, _ := caller.isValidUser(service.Id, "service"); !valid {
|
||||
logger.Println("serviceAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return nil
|
||||
}
|
||||
|
||||
filter := bson.M{"_id": service.Id}
|
||||
@ -249,118 +324,60 @@ func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (caller apiCaller) accountAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
func (caller apiCaller) maintenanceAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
mg := caller.mg
|
||||
queryvals := r.URL.Query()
|
||||
if r.Method == "GET" {
|
||||
service := queryvals.Get("service")
|
||||
if len(service) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if valid, _ := caller.isValidUser(service, "account"); !valid {
|
||||
logger.Println("accountAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return nil
|
||||
}
|
||||
|
||||
var accdoc primitive.M
|
||||
if v := queryvals.Get("accid"); len(v) == 0 {
|
||||
email := queryvals.Get("email")
|
||||
platform := queryvals.Get("platform")
|
||||
if len(email) == 0 || len(platform) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
found, err := mg.mongoClient.FindOne(CollectionLink, bson.M{
|
||||
"email": email,
|
||||
"platform": platform,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if found == nil {
|
||||
return nil
|
||||
}
|
||||
if idobj, ok := found["_id"]; ok {
|
||||
svcdoc, err := mg.mongoClient.FindOne(common.CollectionName(service), bson.M{
|
||||
"_id": idobj,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if svcdoc != nil {
|
||||
found["accid"] = svcdoc["accid"]
|
||||
}
|
||||
|
||||
accdoc = found
|
||||
}
|
||||
} else {
|
||||
accid, err := primitive.ObjectIDFromHex(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
svcdoc, err := mg.mongoClient.FindOne(common.CollectionName(service), bson.M{
|
||||
"accid": accid,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
found, err := mg.mongoClient.FindOne(CollectionLink, bson.M{
|
||||
"_id": svcdoc["_id"],
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if found != nil {
|
||||
found["accid"] = accid
|
||||
}
|
||||
accdoc = found
|
||||
}
|
||||
|
||||
if accdoc != nil {
|
||||
accdoc["code"] = service
|
||||
delete(accdoc, "uid")
|
||||
delete(accdoc, "_id")
|
||||
|
||||
var bi blockinfo
|
||||
if err := mg.mongoClient.FindOneAs(CollectionBlock, bson.M{
|
||||
"code": service,
|
||||
"accid": accdoc["accid"],
|
||||
}, &bi); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !bi.Start.Time().IsZero() && bi.End.Time().After(time.Now().UTC()) {
|
||||
accdoc["blocked"] = bi
|
||||
}
|
||||
return json.NewEncoder(w).Encode(accdoc)
|
||||
}
|
||||
w.Write(mg.service().divisionsSerialized)
|
||||
} else if r.Method == "POST" {
|
||||
var account struct {
|
||||
Code string
|
||||
Accid string
|
||||
Blocked blockinfo
|
||||
}
|
||||
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
if err := json.Unmarshal(body, &account); err != nil {
|
||||
var divs map[string]*Division
|
||||
dec := json.NewDecoder(r.Body)
|
||||
if err := dec.Decode(&divs); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return err
|
||||
}
|
||||
|
||||
accid, _ := primitive.ObjectIDFromHex(account.Accid)
|
||||
if !account.Blocked.Start.Time().IsZero() && account.Blocked.Start.Time().After(time.Now().UTC()) {
|
||||
if _, _, err := mg.mongoClient.Update(CollectionBlock, bson.M{
|
||||
"code": account.Code,
|
||||
"accid": accid,
|
||||
}, bson.M{
|
||||
"$set": account.Blocked,
|
||||
}, options.Update().SetUpsert(true)); err != nil {
|
||||
return err
|
||||
}
|
||||
_, _, err := mg.mongoClient.Update(CollectionService, bson.M{
|
||||
"_id": mg.service().Id,
|
||||
}, bson.M{
|
||||
"$set": bson.M{"divisions": divs},
|
||||
}, options.Update().SetUpsert(false))
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (caller apiCaller) couponAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
switch r.Method {
|
||||
case "PUT":
|
||||
// 쿠폰 생성
|
||||
logger.Println("begin generateCoupons")
|
||||
generateCoupons(caller.mg.mongoClient, w, r)
|
||||
|
||||
case "POST":
|
||||
// TODO : 쿠폰 사용
|
||||
// 쿠폰 사용 표시 해주고 내용을 응답
|
||||
logger.Println("begin useCoupon")
|
||||
useCoupon(caller.mg.mongoClient, w, r)
|
||||
|
||||
case "GET":
|
||||
// 쿠폰 조회
|
||||
if r.Form.Has("code") {
|
||||
// 쿠폰 코드 조회
|
||||
logger.Println("begin queryCoupon")
|
||||
queryCoupon(caller.mg.mongoClient, w, r)
|
||||
} else if r.Form.Has("name") {
|
||||
// 쿠폰 코드 다운
|
||||
logger.Println("begin downloadCoupons")
|
||||
downloadCoupons(caller.mg.mongoClient, w, r)
|
||||
} else {
|
||||
// 쿠폰 이름 목록
|
||||
logger.Println("begin listAllCouponNames")
|
||||
listAllCouponNames(caller.mg.mongoClient, w, r)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -370,24 +387,61 @@ var errApiTokenMissing = errors.New("mg-x-api-token is missing")
|
||||
|
||||
func (caller apiCaller) configAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
mg := caller.mg
|
||||
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
||||
if len(apitoken) == 0 {
|
||||
return errApiTokenMissing
|
||||
}
|
||||
|
||||
if _, exists := mg.apiTokenToService.get(apitoken); !exists {
|
||||
return fmt.Errorf("mg-x-api-token is not valid : %s", apitoken)
|
||||
if !*devflag {
|
||||
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
||||
if len(apitoken) == 0 {
|
||||
return errApiTokenMissing
|
||||
}
|
||||
|
||||
apitokenObj, _ := primitive.ObjectIDFromHex(apitoken)
|
||||
if !mg.service().isValidToken(apitokenObj) {
|
||||
return fmt.Errorf("mg-x-api-token is not valid : %s", apitoken)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var noauth = flag.Bool("noauth", false, "")
|
||||
func (caller apiCaller) lockcreatecharAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
mg, err := caller.mg.mongoClient.FindAll(CollectionService, bson.M{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
haschr, _ := gocommon.ReadStringFormValue(r.Form, "haschr")
|
||||
|
||||
locked := make(map[string]any)
|
||||
if haschr == "true" {
|
||||
locked["lock"] = false
|
||||
} else {
|
||||
curregion, _ := gocommon.ReadStringFormValue(r.Form, "region")
|
||||
|
||||
for _, regioninfo := range mg {
|
||||
region := regioninfo["divisions"].(primitive.M)
|
||||
for idx, rl := range region {
|
||||
if idx == curregion {
|
||||
if rl.(primitive.M)["lockcreatechar"].(bool) {
|
||||
locked["lock"] = true
|
||||
} else {
|
||||
locked["lock"] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create, _ := json.Marshal(locked)
|
||||
w.Write(create)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type apiCaller struct {
|
||||
userinfo map[string]any
|
||||
admins map[string]bool
|
||||
mg *Maingate
|
||||
userinfo map[string]any
|
||||
globalAdmins map[string]bool
|
||||
mg *Maingate
|
||||
apiToken primitive.ObjectID
|
||||
}
|
||||
|
||||
func (mg *Maingate) api(w http.ResponseWriter, r *http.Request) {
|
||||
@ -403,9 +457,11 @@ func (mg *Maingate) api(w http.ResponseWriter, r *http.Request) {
|
||||
r.Body.Close()
|
||||
}()
|
||||
|
||||
r.ParseMultipartForm(32 << 20)
|
||||
|
||||
var userinfo map[string]any
|
||||
|
||||
if !*noauth {
|
||||
if !*devflag {
|
||||
authheader := r.Header.Get("Authorization")
|
||||
if len(authheader) == 0 {
|
||||
logger.Println("Authorization header is not valid :", authheader)
|
||||
@ -439,20 +495,35 @@ func (mg *Maingate) api(w http.ResponseWriter, r *http.Request) {
|
||||
ptr := atomic.LoadPointer(&mg.admins)
|
||||
adminsptr := (*globalAdmins)(ptr)
|
||||
|
||||
if adminsptr.modtime != common.ConfigModTime() {
|
||||
if adminsptr.modtime != gocommon.ConfigModTime() {
|
||||
var config globalAdmins
|
||||
if err := common.LoadConfig(&config); err == nil {
|
||||
if err := gocommon.LoadConfig(&config); err == nil {
|
||||
config.parse()
|
||||
adminsptr = &config
|
||||
atomic.StorePointer(&mg.admins, unsafe.Pointer(adminsptr))
|
||||
}
|
||||
}
|
||||
|
||||
var apiTokenObj primitive.ObjectID
|
||||
if !*devflag {
|
||||
apiToken := r.Header.Get("MG-X-API-TOKEN")
|
||||
if len(apiToken) > 0 {
|
||||
obj, err := primitive.ObjectIDFromHex(apiToken)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
apiTokenObj = obj
|
||||
}
|
||||
}
|
||||
|
||||
logger.Println("api call :", r.URL.Path, r.Method, r.URL.Query(), userinfo)
|
||||
caller := apiCaller{
|
||||
userinfo: userinfo,
|
||||
admins: adminsptr.emails,
|
||||
mg: mg,
|
||||
userinfo: userinfo,
|
||||
globalAdmins: adminsptr.emails,
|
||||
mg: mg,
|
||||
apiToken: apiTokenObj,
|
||||
}
|
||||
|
||||
var err error
|
||||
@ -462,8 +533,18 @@ func (mg *Maingate) api(w http.ResponseWriter, r *http.Request) {
|
||||
err = caller.whitelistAPI(w, r)
|
||||
} else if strings.HasSuffix(r.URL.Path, "/config") {
|
||||
err = caller.configAPI(w, r)
|
||||
} else if strings.HasSuffix(r.URL.Path, "/account") {
|
||||
err = caller.accountAPI(w, r)
|
||||
} else if strings.HasSuffix(r.URL.Path, "/upload") {
|
||||
err = caller.uploadAPI(w, r)
|
||||
} else if strings.HasSuffix(r.URL.Path, "/maintenance") {
|
||||
err = caller.maintenanceAPI(w, r)
|
||||
} else if strings.HasSuffix(r.URL.Path, "/files") {
|
||||
err = caller.filesAPI(w, r)
|
||||
} else if strings.HasSuffix(r.URL.Path, "/block") {
|
||||
err = caller.blockAPI(w, r)
|
||||
} else if strings.HasSuffix(r.URL.Path, "/coupon") {
|
||||
err = caller.couponAPI(w, r)
|
||||
} else if strings.HasSuffix(r.URL.Path, "/lockcreatechar") {
|
||||
err = caller.lockcreatecharAPI(w, r)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
372
core/api_coupon.go
Normal file
372
core/api_coupon.go
Normal file
@ -0,0 +1,372 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"repositories.action2quare.com/ayo/gocommon"
|
||||
coupon "repositories.action2quare.com/ayo/gocommon/coupon"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
CollectionCoupon = gocommon.CollectionName("coupon")
|
||||
CollectionCouponUse = gocommon.CollectionName("coupon_use")
|
||||
)
|
||||
|
||||
type couponDoc struct {
|
||||
Name string `json:"name" bson:"name"`
|
||||
Effect string `json:"effect" bson:"effect"`
|
||||
Desc string `json:"desc" bson:"desc"`
|
||||
Total int64 `json:"total" bson:"total"`
|
||||
Remains []string `json:"remains,omitempty" bson:"remains,omitempty"`
|
||||
Used []string `json:"used,omitempty" bson:"used,omitempty"`
|
||||
}
|
||||
|
||||
func makeCouponKey(roundnum uint32, uid []byte) string {
|
||||
left := binary.BigEndian.Uint16(uid[0:2])
|
||||
right := binary.BigEndian.Uint16(uid[2:4])
|
||||
multi := uint32(left) * uint32(right)
|
||||
xor := roundnum ^ multi
|
||||
|
||||
final := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint32(final, xor)
|
||||
copy(final[4:], uid)
|
||||
return fmt.Sprintf("%s-%s-%s-%s", hex.EncodeToString(final[0:2]), hex.EncodeToString(final[2:4]), hex.EncodeToString(final[4:6]), hex.EncodeToString(final[6:8]))
|
||||
}
|
||||
|
||||
func makeCouponCodes(name string, count int) (string, map[string]string) {
|
||||
checkunique := make(map[string]bool)
|
||||
keys := make(map[string]string)
|
||||
uid := make([]byte, 4)
|
||||
|
||||
roundHash, roundnum := coupon.MakeCouponRoundHash(name)
|
||||
seed := time.Now().UnixNano()
|
||||
|
||||
for len(keys) < count {
|
||||
rand.Seed(seed)
|
||||
rand.Read(uid)
|
||||
|
||||
code := makeCouponKey(roundnum, uid)
|
||||
|
||||
if _, ok := checkunique[code]; !ok {
|
||||
checkunique[code] = true
|
||||
keys[hex.EncodeToString(uid)] = code
|
||||
}
|
||||
seed = int64(binary.BigEndian.Uint32(uid))
|
||||
}
|
||||
return roundHash, keys
|
||||
}
|
||||
|
||||
func generateCoupons(mongoClient gocommon.MongoClient, w http.ResponseWriter, r *http.Request) {
|
||||
name, _ := gocommon.ReadStringFormValue(r.Form, "name")
|
||||
effect, _ := gocommon.ReadStringFormValue(r.Form, "effect")
|
||||
count, _ := gocommon.ReadIntegerFormValue(r.Form, "count")
|
||||
desc, _ := gocommon.ReadStringFormValue(r.Form, "desc")
|
||||
|
||||
if count == 0 {
|
||||
logger.Println("[generateCoupons] count == 0")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
roundHash, _ := coupon.MakeCouponRoundHash(name)
|
||||
roundObj, _ := primitive.ObjectIDFromHex(roundHash + roundHash + roundHash)
|
||||
|
||||
if count < 0 {
|
||||
// 무한 쿠폰이므로 그냥 문서 생성해 주고 끝
|
||||
if _, _, err := mongoClient.Update(CollectionCoupon, bson.M{
|
||||
"_id": roundObj,
|
||||
}, bson.M{
|
||||
"$set": &couponDoc{
|
||||
Name: name,
|
||||
Effect: effect,
|
||||
Desc: desc,
|
||||
Total: -1,
|
||||
},
|
||||
}, options.Update().SetUpsert(true)); err != nil {
|
||||
logger.Println("[generateCoupons] Update failed :", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// effect가 비어있으면 기존의 roundName에 갯수를 추가해 준다
|
||||
// effect가 비어있지 않으면 roundName이 겹쳐서는 안된다.
|
||||
coupondoc, err := mongoClient.FindOne(CollectionCoupon, bson.M{"_id": roundObj})
|
||||
if err != nil {
|
||||
logger.Println("[generateCoupons] FindOne failed :", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
lastKeys := make(map[string]bool)
|
||||
if coupondoc != nil {
|
||||
if r, ok := coupondoc["remains"]; ok {
|
||||
remains := r.(primitive.A)
|
||||
for _, uid := range remains {
|
||||
lastKeys[uid.(string)] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issuedKeys := make(map[string]string)
|
||||
for len(issuedKeys) < int(count) {
|
||||
_, vs := makeCouponCodes(name, int(count)-len(issuedKeys))
|
||||
for k, v := range vs {
|
||||
if _, ok := lastKeys[k]; !ok {
|
||||
// 기존 키와 중복되지 않는 것만
|
||||
issuedKeys[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var coupons []string
|
||||
var uids []string
|
||||
for uid, code := range issuedKeys {
|
||||
uids = append(uids, uid)
|
||||
coupons = append(coupons, code)
|
||||
}
|
||||
|
||||
if coupondoc != nil {
|
||||
_, _, err = mongoClient.Update(CollectionCoupon, bson.M{
|
||||
"_id": roundObj,
|
||||
}, bson.M{
|
||||
"$push": bson.M{"remains": bson.M{"$each": uids}},
|
||||
"$inc": bson.M{"total": count},
|
||||
}, options.Update().SetUpsert(true))
|
||||
} else {
|
||||
_, _, err = mongoClient.Update(CollectionCoupon, bson.M{
|
||||
"_id": roundObj,
|
||||
}, bson.M{
|
||||
"$push": bson.M{"remains": bson.M{"$each": uids}},
|
||||
"$set": couponDoc{
|
||||
Name: name,
|
||||
Effect: effect,
|
||||
Desc: desc,
|
||||
Total: count,
|
||||
},
|
||||
}, options.Update().SetUpsert(true))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.Println("[generateCoupons] Update failed :", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(w)
|
||||
enc.Encode(coupons)
|
||||
}
|
||||
|
||||
func downloadCoupons(mongoClient gocommon.MongoClient, w http.ResponseWriter, r *http.Request) {
|
||||
name, _ := gocommon.ReadStringFormValue(r.Form, "name")
|
||||
if len(name) == 0 {
|
||||
logger.Println("[downloadCoupons] name is empty")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
round, _ := coupon.MakeCouponRoundHash(name)
|
||||
|
||||
roundObj, err := primitive.ObjectIDFromHex(round + round + round)
|
||||
if err != nil {
|
||||
// 유효하지 않은 형식의 code
|
||||
logger.Println("[downloadCoupons] ObjectIDFromHex failed :", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var coupon couponDoc
|
||||
if err := mongoClient.FindOneAs(CollectionCoupon, bson.M{
|
||||
"_id": roundObj,
|
||||
}, &coupon, options.FindOne().SetProjection(bson.M{"_id": 0, "remains": 1})); err != nil {
|
||||
logger.Println("[downloadCoupons] FindOne failed :", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
roundnum := binary.BigEndian.Uint32(roundObj[:])
|
||||
var coupons []string
|
||||
for _, uid := range coupon.Remains {
|
||||
coupons = append(coupons, makeCouponKey(roundnum, []byte(uid)))
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(w)
|
||||
enc.Encode(coupons)
|
||||
}
|
||||
|
||||
func queryCoupon(mongoClient gocommon.MongoClient, w http.ResponseWriter, r *http.Request) {
|
||||
code, _ := gocommon.ReadStringFormValue(r.Form, "code")
|
||||
if len(code) == 0 {
|
||||
logger.Println("[queryCoupon] code is empty")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
round, _ := coupon.DisolveCouponCode(code)
|
||||
if len(round) == 0 {
|
||||
// 유효하지 않은 형식의 code
|
||||
// 쿠폰 이름일 수 있으므로 round hash를 계산한다.
|
||||
round, _ = coupon.MakeCouponRoundHash(code)
|
||||
}
|
||||
|
||||
roundObj, err := primitive.ObjectIDFromHex(round + round + round)
|
||||
if err != nil {
|
||||
// 유효하지 않은 형식의 code
|
||||
logger.Println("[queryCoupon] ObjectIDFromHex failed :", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var coupon couponDoc
|
||||
if err := mongoClient.FindOneAs(CollectionCoupon, bson.M{
|
||||
"_id": roundObj,
|
||||
}, &coupon, options.FindOne().SetProjection(bson.M{"effect": 1, "name": 1, "reason": 1, "total": 1, "desc": 1}).SetReturnKey(false)); err != nil {
|
||||
logger.Println("[queryCoupon] FindOneAs failed :", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(w)
|
||||
enc.Encode(coupon)
|
||||
}
|
||||
|
||||
func listAllCouponNames(mongoClient gocommon.MongoClient, w http.ResponseWriter, r *http.Request) {
|
||||
all, err := mongoClient.FindAll(CollectionCoupon, bson.M{}, options.Find().SetProjection(bson.M{"name": 1}))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
var names []string
|
||||
for _, doc := range all {
|
||||
names = append(names, doc["name"].(string))
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(w)
|
||||
enc.Encode(names)
|
||||
}
|
||||
|
||||
func useCoupon(mongoClient gocommon.MongoClient, w http.ResponseWriter, r *http.Request) {
|
||||
acc, ok := gocommon.ReadObjectIDFormValue(r.Form, "accid")
|
||||
if !ok || acc.IsZero() {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
code, _ := gocommon.ReadStringFormValue(r.Form, "code")
|
||||
code = strings.TrimSpace(code)
|
||||
if len(code) == 0 {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
round, key := coupon.DisolveCouponCode(code)
|
||||
if len(round) == 0 {
|
||||
// couponId가 쿠폰 이름일 수도 있다. 무한 쿠폰
|
||||
round, _ = coupon.MakeCouponRoundHash(code)
|
||||
}
|
||||
|
||||
// 1. 내가 이 라운드의 쿠폰을 쓴 적이 있나
|
||||
already, err := mongoClient.Exists(CollectionCouponUse, bson.M{
|
||||
"_id": acc,
|
||||
"rounds": round,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if already {
|
||||
// 이미 이 라운드의 쿠폰을 사용한 적이 있다.
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
return
|
||||
}
|
||||
|
||||
var coupon couponDoc
|
||||
roundObj, _ := primitive.ObjectIDFromHex(round + round + round)
|
||||
if len(key) == 0 {
|
||||
// 무한 쿠폰일 수 있으므로 존재하는지 확인
|
||||
if err := mongoClient.FindOneAs(CollectionCoupon, bson.M{
|
||||
"_id": roundObj,
|
||||
}, &coupon, options.FindOne().SetProjection(bson.M{"_id": 0, "effect": 1, "name": 1, "reason": 1, "total": 1})); err != nil {
|
||||
logger.Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if coupon.Total > 0 {
|
||||
// 무한 쿠폰 아니네?
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// 2. 쿠폰을 하나 꺼냄
|
||||
matched, _, err := mongoClient.Update(CollectionCoupon, bson.M{
|
||||
"_id": roundObj,
|
||||
}, bson.M{
|
||||
"$pull": bson.M{"remains": key},
|
||||
})
|
||||
if err != nil {
|
||||
logger.Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if !matched {
|
||||
// 쿠폰이 없다.
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// 3. round의 효과 읽기
|
||||
if err := mongoClient.FindOneAndUpdateAs(CollectionCoupon, bson.M{
|
||||
"_id": roundObj,
|
||||
}, bson.M{
|
||||
"$push": bson.M{"used": key},
|
||||
}, &coupon, options.FindOneAndUpdate().SetProjection(bson.M{"effect": 1})); err != nil {
|
||||
logger.Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(coupon.Effect) == 0 {
|
||||
// 쿠폰이 없네?
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// 4. 쿠폰은 사용한 것으로 표시
|
||||
// 이제 이 아래에서 실패하면 이 쿠폰은 못쓴다.
|
||||
updated, _, err := mongoClient.Update(CollectionCouponUse, bson.M{
|
||||
"_id": acc,
|
||||
}, bson.M{
|
||||
"$push": bson.M{"rounds": round},
|
||||
"$set": bson.M{round + ".id": code},
|
||||
"$currentDate": bson.M{round + ".ts": true},
|
||||
}, options.Update().SetUpsert(true))
|
||||
|
||||
if err != nil {
|
||||
logger.Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if !updated {
|
||||
logger.Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte(coupon.Effect))
|
||||
}
|
||||
39
core/api_test.go
Normal file
39
core/api_test.go
Normal file
@ -0,0 +1,39 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"repositories.action2quare.com/ayo/gocommon"
|
||||
)
|
||||
|
||||
func TestMakeLocalUniqueId(t *testing.T) {
|
||||
ts := int64(1690815600)
|
||||
start := primitive.NewDateTimeFromTime(time.Unix(ts, 0))
|
||||
ts = int64(1693493999)
|
||||
end := primitive.NewDateTimeFromTime(time.Unix(ts, 0))
|
||||
|
||||
fmt.Println(start.Time().Format(time.RFC3339))
|
||||
fmt.Println(end.Time().Format(time.RFC3339))
|
||||
|
||||
mongoClient, err := gocommon.NewMongoClient(context.Background(), "mongodb://121.134.91.160:27018/mountain-maingate?replicaSet=rs0&retrywrites=true", "maingate")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
bi := blockinfo{
|
||||
Start: start,
|
||||
End: end,
|
||||
Reason: "test",
|
||||
}
|
||||
mongoClient.Update(CollectionBlock, bson.M{
|
||||
"_id": primitive.NewObjectID(),
|
||||
}, bson.M{
|
||||
"$set": &bi,
|
||||
}, options.Update().SetUpsert(true))
|
||||
}
|
||||
646
core/maingate.go
646
core/maingate.go
@ -7,21 +7,22 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"text/template"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/common"
|
||||
"repositories.action2quare.com/ayo/go-ayo/logger"
|
||||
"repositories.action2quare.com/ayo/gocommon"
|
||||
"repositories.action2quare.com/ayo/gocommon/flagx"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
|
||||
"github.com/golang-jwt/jwt"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
@ -34,21 +35,26 @@ import (
|
||||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
var devflag = flagx.Bool("dev", false, "")
|
||||
var noauth = flagx.Bool("noauth", false, "")
|
||||
|
||||
var (
|
||||
CollectionLink = common.CollectionName("link")
|
||||
CollectionAuth = common.CollectionName("auth")
|
||||
CollectionWhitelist = common.CollectionName("whitelist")
|
||||
CollectionService = common.CollectionName("service")
|
||||
CollectionBlock = common.CollectionName("block")
|
||||
CollectionPlatformLoginToken = common.CollectionName("platform_login_token") //-- 각 플랫폼에 로그인 및 권한 받아오는 과정에 사용하는 Key
|
||||
CollectionUserToken = common.CollectionName("usertoken")
|
||||
CollectionGamepotUserInfo = common.CollectionName("gamepot_userinfo") //-- 클라로부터 수집된 gamepot 정보 - server to server로 유효성이 검증되진 않았지만 수집은 한다.
|
||||
CollectionFirebaseUserInfo = common.CollectionName("firebase_userinfo") //-- Firebase UserInfo
|
||||
CollectionLink = gocommon.CollectionName("link")
|
||||
CollectionAuth = gocommon.CollectionName("auth")
|
||||
CollectionWhitelist = gocommon.CollectionName("whitelist")
|
||||
CollectionService = gocommon.CollectionName("service")
|
||||
CollectionAccount = gocommon.CollectionName("account")
|
||||
CollectionFile = gocommon.CollectionName("file")
|
||||
CollectionBlock = gocommon.CollectionName("block")
|
||||
CollectionPlatformLoginToken = gocommon.CollectionName("platform_login_token") //-- 각 플랫폼에 로그인 및 권한 받아오는 과정에 사용하는 Key
|
||||
CollectionUserToken = gocommon.CollectionName("usertoken")
|
||||
CollectionGamepotUserInfo = gocommon.CollectionName("gamepot_userinfo") //-- 클라로부터 수집된 gamepot 정보 - server to server로 유효성이 검증되진 않았지만 수집은 한다.
|
||||
CollectionFirebaseUserInfo = gocommon.CollectionName("firebase_userinfo") //-- Firebase UserInfo
|
||||
)
|
||||
|
||||
const (
|
||||
AuthPlatformSteamSDK = "steam"
|
||||
AuthPlatformFirebaseAuth = "firebase"
|
||||
AuthPlatformGamepot = "gamepot"
|
||||
AuthPlatformGoogle = "google"
|
||||
AuthPlatformMicrosoft = "microsoft"
|
||||
AuthPlatformApple = "apple"
|
||||
@ -61,7 +67,7 @@ const (
|
||||
)
|
||||
|
||||
func SessionTTL() time.Duration {
|
||||
if *common.Devflag {
|
||||
if *devflag {
|
||||
return sessionTTLDev
|
||||
}
|
||||
|
||||
@ -69,25 +75,10 @@ func SessionTTL() time.Duration {
|
||||
}
|
||||
|
||||
type mongoAuthCell struct {
|
||||
src *common.Authinfo
|
||||
src *gocommon.Authinfo
|
||||
}
|
||||
|
||||
func init() {
|
||||
if *common.Devflag {
|
||||
hostname, _ := os.Hostname()
|
||||
CollectionLink = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionLink)))
|
||||
CollectionAuth = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionAuth)))
|
||||
CollectionWhitelist = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionWhitelist)))
|
||||
CollectionService = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionService)))
|
||||
CollectionBlock = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionBlock)))
|
||||
CollectionPlatformLoginToken = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionPlatformLoginToken)))
|
||||
CollectionUserToken = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionUserToken)))
|
||||
CollectionGamepotUserInfo = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionGamepotUserInfo)))
|
||||
CollectionFirebaseUserInfo = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionFirebaseUserInfo)))
|
||||
}
|
||||
}
|
||||
|
||||
func (ac *mongoAuthCell) ToAuthinfo() *common.Authinfo {
|
||||
func (ac *mongoAuthCell) ToAuthinfo() *gocommon.Authinfo {
|
||||
if ac.src == nil {
|
||||
logger.Error("mongoAuthCell ToAuthinfo failed. ac.src is nil")
|
||||
}
|
||||
@ -99,15 +90,15 @@ func (ac *mongoAuthCell) ToBytes() []byte {
|
||||
return bt
|
||||
}
|
||||
|
||||
func makeAuthCollection(mongoClient common.MongoClient, sessionTTL time.Duration) *common.AuthCollection {
|
||||
authcoll := common.MakeAuthCollection(sessionTTL)
|
||||
func makeAuthCollection(mongoClient gocommon.MongoClient, sessionTTL time.Duration) *gocommon.AuthCollection {
|
||||
authcoll := gocommon.MakeAuthCollection(sessionTTL)
|
||||
authcoll.SessionRemoved = func(sk string) {
|
||||
skid, _ := primitive.ObjectIDFromHex(sk)
|
||||
mongoClient.Delete(CollectionAuth, bson.M{
|
||||
"sk": skid,
|
||||
})
|
||||
}
|
||||
authcoll.QuerySession = func(sk string, token string) common.AuthinfoCell {
|
||||
authcoll.QuerySession = func(sk string, token string) gocommon.AuthinfoCell {
|
||||
skid, _ := primitive.ObjectIDFromHex(sk)
|
||||
var outcell mongoAuthCell
|
||||
err := mongoClient.FindOneAs(CollectionAuth, bson.M{
|
||||
@ -129,37 +120,12 @@ func makeAuthCollection(mongoClient common.MongoClient, sessionTTL time.Duration
|
||||
return authcoll
|
||||
}
|
||||
|
||||
type apiTokenMap struct {
|
||||
sync.Mutex
|
||||
tokenToService map[string]string
|
||||
}
|
||||
|
||||
func (tm *apiTokenMap) add(token string, serviceCode string) {
|
||||
tm.Lock()
|
||||
defer tm.Unlock()
|
||||
|
||||
tm.tokenToService[token] = serviceCode
|
||||
}
|
||||
|
||||
func (tm *apiTokenMap) remove(token string) {
|
||||
tm.Lock()
|
||||
defer tm.Unlock()
|
||||
|
||||
delete(tm.tokenToService, token)
|
||||
}
|
||||
|
||||
func (tm *apiTokenMap) get(token string) (code string, exists bool) {
|
||||
tm.Lock()
|
||||
defer tm.Unlock()
|
||||
|
||||
code, exists = tm.tokenToService[token]
|
||||
return
|
||||
}
|
||||
|
||||
type maingateConfig struct {
|
||||
Mongo string `json:"maingate_mongodb_url"`
|
||||
SessionTTL int64 `json:"maingate_session_ttl"`
|
||||
Autologin_ttl int64 `json:"autologin_ttl"`
|
||||
AccDelTTL int64 `json:"acc_del_ttl"`
|
||||
MaximumNumLinkAccount int64 `json:"maximum_num_link_account"`
|
||||
RedirectBaseUrl string `json:"redirect_base_url"`
|
||||
GoogleClientId string `json:"google_client_id"`
|
||||
GoogleClientSecret string `json:"google_client_secret"`
|
||||
@ -177,6 +143,20 @@ type maingateConfig struct {
|
||||
GamepotProjectId string `json:"gamepot_project_id"`
|
||||
GamepotLoginCheckAPIURL string `json:"gamepot_logincheckapi_url"`
|
||||
FirebaseAdminSDKCredentialFile string `json:"firebase_admin_sdk_credentialfile"`
|
||||
SteamAppId string `json:"steam_app_id"`
|
||||
SteamPublisherAuthKey string `json:"steam_publisher_authkey"`
|
||||
Firebase_Google_Analytics_JS_SDK_Config
|
||||
}
|
||||
|
||||
type Firebase_Google_Analytics_JS_SDK_Config struct {
|
||||
FGA_apiKey string `json:"firebase_google_analytics_jssdk_apikey"`
|
||||
FGA_authDomain string `json:"firebase_google_analytics_jssdk_authdomain"`
|
||||
FGA_databaseURL string `json:"firebase_google_analytics_jssdk_databaseurl"`
|
||||
FGA_projectId string `json:"firebase_google_analytics_jssdk_projectid"`
|
||||
FGA_storageBucket string `json:"firebase_google_analytics_jssdk_storagebucket"`
|
||||
FGA_messagingSenderId string `json:"firebase_google_analytics_jssdk_messagingsenderid"`
|
||||
FGA_appId string `json:"firebase_google_analytics_jssdk_apiid"`
|
||||
FGA_measurementId string `json:"ffirebase_google_analytics_jssdk_measurementid"`
|
||||
}
|
||||
|
||||
type globalAdmins struct {
|
||||
@ -191,100 +171,26 @@ func (ga *globalAdmins) parse() {
|
||||
parsed[admin] = true
|
||||
}
|
||||
ga.emails = parsed
|
||||
ga.modtime = common.ConfigModTime()
|
||||
}
|
||||
|
||||
type servicelist struct {
|
||||
services unsafe.Pointer
|
||||
}
|
||||
|
||||
func (sl *servicelist) init(total []*serviceDescription) error {
|
||||
next := make(map[string]*serviceDescription)
|
||||
for _, service := range total {
|
||||
next[service.ServiceName] = service
|
||||
}
|
||||
|
||||
atomic.StorePointer(&sl.services, unsafe.Pointer(&next))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sl *servicelist) add(s *serviceDescription) {
|
||||
ptr := atomic.LoadPointer(&sl.services)
|
||||
src := (*map[string]*serviceDescription)(ptr)
|
||||
|
||||
next := map[string]*serviceDescription{}
|
||||
for k, v := range *src {
|
||||
next[k] = v
|
||||
}
|
||||
next[s.ServiceName] = s
|
||||
atomic.StorePointer(&sl.services, unsafe.Pointer(&next))
|
||||
}
|
||||
|
||||
func (sl *servicelist) get(sn any) *serviceDescription {
|
||||
ptr := atomic.LoadPointer(&sl.services)
|
||||
src := *(*map[string]*serviceDescription)(ptr)
|
||||
|
||||
switch sn := sn.(type) {
|
||||
case string:
|
||||
return src[sn]
|
||||
|
||||
case primitive.ObjectID:
|
||||
for _, desc := range src {
|
||||
if desc.Id == sn {
|
||||
return desc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sl *servicelist) all() map[string]*serviceDescription {
|
||||
ptr := atomic.LoadPointer(&sl.services)
|
||||
src := (*map[string]*serviceDescription)(ptr)
|
||||
|
||||
next := map[string]*serviceDescription{}
|
||||
for k, v := range *src {
|
||||
next[k] = v
|
||||
}
|
||||
|
||||
return next
|
||||
}
|
||||
|
||||
func (sl *servicelist) remove(uid primitive.ObjectID) (out *serviceDescription) {
|
||||
ptr := atomic.LoadPointer(&sl.services)
|
||||
src := (*map[string]*serviceDescription)(ptr)
|
||||
|
||||
next := map[string]*serviceDescription{}
|
||||
var targetkey string
|
||||
out = nil
|
||||
for k, v := range *src {
|
||||
next[k] = v
|
||||
if v.Id == uid {
|
||||
targetkey = k
|
||||
out = v
|
||||
}
|
||||
}
|
||||
delete(next, targetkey)
|
||||
atomic.StorePointer(&sl.services, unsafe.Pointer(&next))
|
||||
return
|
||||
ga.modtime = gocommon.ConfigModTime()
|
||||
}
|
||||
|
||||
// Maingate :
|
||||
type Maingate struct {
|
||||
maingateConfig
|
||||
|
||||
mongoClient common.MongoClient
|
||||
mongoClient gocommon.MongoClient
|
||||
|
||||
auths *gocommon.AuthCollection
|
||||
//services servicelist
|
||||
serviceptr unsafe.Pointer
|
||||
admins unsafe.Pointer
|
||||
wl memberContainerPtr[string, *whitelistmember]
|
||||
bl memberContainerPtr[primitive.ObjectID, *blockinfo]
|
||||
|
||||
auths *common.AuthCollection
|
||||
services servicelist
|
||||
admins unsafe.Pointer
|
||||
apiTokenToService apiTokenMap
|
||||
tokenEndpoints map[string]string
|
||||
authorizationEndpoints map[string]string
|
||||
userinfoEndpoint map[string]string
|
||||
jwksUri map[string]string
|
||||
webTemplate map[string]*template.Template
|
||||
firebaseAppClient *auth.Client
|
||||
firebaseAppContext context.Context
|
||||
}
|
||||
@ -292,12 +198,12 @@ type Maingate struct {
|
||||
// New :
|
||||
func New(ctx context.Context) (*Maingate, error) {
|
||||
var config maingateConfig
|
||||
if err := common.LoadConfig(&config); err != nil {
|
||||
if err := gocommon.LoadConfig(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var admins globalAdmins
|
||||
if err := common.LoadConfig(&admins); err == nil {
|
||||
if err := gocommon.LoadConfig(&admins); err == nil {
|
||||
admins.parse()
|
||||
}
|
||||
|
||||
@ -306,12 +212,8 @@ func New(ctx context.Context) (*Maingate, error) {
|
||||
}
|
||||
|
||||
mg := Maingate{
|
||||
maingateConfig: config,
|
||||
services: servicelist{},
|
||||
admins: unsafe.Pointer(&admins),
|
||||
apiTokenToService: apiTokenMap{
|
||||
tokenToService: make(map[string]string),
|
||||
},
|
||||
maingateConfig: config,
|
||||
admins: unsafe.Pointer(&admins),
|
||||
tokenEndpoints: make(map[string]string),
|
||||
authorizationEndpoints: make(map[string]string),
|
||||
userinfoEndpoint: make(map[string]string),
|
||||
@ -320,26 +222,32 @@ func New(ctx context.Context) (*Maingate, error) {
|
||||
|
||||
err := mg.prepare(ctx)
|
||||
if err != nil {
|
||||
logger.Error("mg.prepare() failed :", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opt := option.WithCredentialsFile(mg.FirebaseAdminSDKCredentialFile)
|
||||
firebaseApp, err := firebase.NewApp(context.Background(), nil, opt)
|
||||
if err != nil {
|
||||
logger.Error("firebase admin error initializing app failed :", err)
|
||||
return nil, err
|
||||
}
|
||||
if !*noauth {
|
||||
opt := option.WithCredentialsFile(mg.FirebaseAdminSDKCredentialFile)
|
||||
firebaseApp, err := firebase.NewApp(context.Background(), nil, opt)
|
||||
if err != nil {
|
||||
logger.Error("firebase admin error initializing app failed :", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mg.firebaseAppContext = ctx
|
||||
mg.firebaseAppClient, err = firebaseApp.Auth(mg.firebaseAppContext)
|
||||
if err != nil {
|
||||
logger.Println("FirebaseAppClient error getting Auth client:", err)
|
||||
mg.firebaseAppContext = ctx
|
||||
mg.firebaseAppClient, err = firebaseApp.Auth(mg.firebaseAppContext)
|
||||
if err != nil {
|
||||
logger.Println("FirebaseAppClient error getting Auth client:", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &mg, nil
|
||||
}
|
||||
|
||||
func (mg *Maingate) service() *serviceDescription {
|
||||
valptr := atomic.LoadPointer(&mg.serviceptr)
|
||||
return (*serviceDescription)(valptr)
|
||||
}
|
||||
|
||||
func (mg *Maingate) Destructor() {
|
||||
logger.Println("maingate.Destructor")
|
||||
mg.mongoClient.Close()
|
||||
@ -393,185 +301,306 @@ func (mg *Maingate) discoverOpenIdConfiguration(name string, url string) error {
|
||||
|
||||
}
|
||||
|
||||
func makeErrorWithStack(err error) error {
|
||||
return fmt.Errorf("%s\n%s", err.Error(), string(debug.Stack()))
|
||||
}
|
||||
|
||||
func (mg *Maingate) prepare(context context.Context) (err error) {
|
||||
if err := mg.discoverOpenIdConfiguration(AuthPlatformMicrosoft, "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
if err := mg.discoverOpenIdConfiguration("google", "https://accounts.google.com/.well-known/openid-configuration"); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
mg.webTemplate = make(map[string]*template.Template)
|
||||
mg.webTemplate[AuthPlatformGamepot] = template.Must(template.ParseFiles("www/gamepot.html"))
|
||||
|
||||
// redis에서 env를 가져온 후에
|
||||
mg.mongoClient, err = common.NewMongoClient(context, mg.Mongo, "maingate")
|
||||
mg.mongoClient, err = gocommon.NewMongoClient(context, mg.Mongo, "maingate")
|
||||
if err != nil {
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionCouponUse, map[string]bson.D{
|
||||
"idrounds": {{Key: "_id", Value: 1}, {Key: "rounds", Value: 1}},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionAuth, map[string]bson.D{
|
||||
"skonly": {{Key: "sk", Value: 1}},
|
||||
}); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionLink, map[string]bson.D{
|
||||
"platformuid": {{Key: "platform", Value: 1}, {Key: "uid", Value: 1}},
|
||||
}); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionLink, map[string]bson.D{
|
||||
"emailplatform": {{Key: "email", Value: 1}, {Key: "platform", Value: 1}},
|
||||
}); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeIndices(CollectionWhitelist, map[string]bson.D{
|
||||
"service": {{Key: "service", Value: 1}},
|
||||
if err = mg.mongoClient.MakeIndices(CollectionAccount, map[string]bson.D{
|
||||
"accid": {{Key: "accid", Value: 1}},
|
||||
}); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionFile, map[string]bson.D{
|
||||
"keyonly": {{Key: "key", Value: 1}},
|
||||
}); err != nil {
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeExpireIndex(CollectionAccount, int32(mg.AccDelTTL)); err != nil {
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeExpireIndex(CollectionLink, int32(mg.AccDelTTL)); err != nil {
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
// Delete대신 _ts로 expire시킴. pipeline에 삭제 알려주기 위함
|
||||
if err = mg.mongoClient.MakeExpireIndex(CollectionWhitelist, 10); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeExpireIndex(CollectionAuth, int32(mg.SessionTTL+300)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionBlock, map[string]bson.D{
|
||||
"codeaccid": {{Key: "code", Value: 1}, {Key: "accid", Value: 1}},
|
||||
}); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeExpireIndex(CollectionBlock, int32(3)); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionPlatformLoginToken, map[string]bson.D{
|
||||
"platformauthtoken": {{Key: "platform", Value: 1}, {Key: "key", Value: 1}},
|
||||
}); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeExpireIndex(CollectionPlatformLoginToken, int32(mg.SessionTTL+300)); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionUserToken, map[string]bson.D{
|
||||
"platformusertoken": {{Key: "platform", Value: 1}, {Key: "userid", Value: 1}},
|
||||
}); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionGamepotUserInfo, map[string]bson.D{
|
||||
"gamepotuserid": {{Key: "gamepotuserid", Value: 1}},
|
||||
}); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionFirebaseUserInfo, map[string]bson.D{
|
||||
"firebaseuserid": {{Key: "firebaseuserid", Value: 1}},
|
||||
}); err != nil {
|
||||
return err
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
mg.auths = makeAuthCollection(mg.mongoClient, time.Duration(mg.SessionTTL*int64(time.Second)))
|
||||
|
||||
var preall []struct {
|
||||
Link string `bson:"link"`
|
||||
Id primitive.ObjectID `bson:"_id"`
|
||||
}
|
||||
if err = mg.mongoClient.FindAllAs(CollectionFile, nil, &preall, options.Find().SetProjection(bson.M{
|
||||
"link": 1,
|
||||
})); err != nil {
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
|
||||
for _, pre := range preall {
|
||||
_, err := os.Stat(pre.Link)
|
||||
if !os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
logger.Println("saving files :", pre.Link)
|
||||
|
||||
var fulldoc FileDocumentDesc
|
||||
err = mg.mongoClient.FindOneAs(CollectionFile, bson.M{
|
||||
"_id": pre.Id,
|
||||
}, &fulldoc)
|
||||
if err != nil {
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
err = fulldoc.Save()
|
||||
if err != nil {
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
}
|
||||
|
||||
var whites []*whitelistmember
|
||||
if err := mg.mongoClient.AllAs(CollectionWhitelist, &whites, options.Find().SetReturnKey(false)); err != nil {
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
mg.wl.init(whites)
|
||||
|
||||
var blocks []*blockinfo
|
||||
if err := mg.mongoClient.AllAs(CollectionBlock, &blocks); err != nil {
|
||||
return makeErrorWithStack(err)
|
||||
}
|
||||
mg.bl.init(blocks)
|
||||
|
||||
go watchAuthCollection(context, mg.auths, mg.mongoClient)
|
||||
go mg.watchWhitelistCollection(context)
|
||||
go mg.wl.watchCollection(context, CollectionWhitelist, mg.mongoClient)
|
||||
go mg.bl.watchCollection(context, CollectionBlock, mg.mongoClient)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func whitelistKey(email string) string {
|
||||
if strings.HasPrefix(email, "*@") {
|
||||
// 도메인 전체 허용
|
||||
return email[2:]
|
||||
}
|
||||
|
||||
return email
|
||||
}
|
||||
|
||||
func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMux, prefix string) error {
|
||||
var allServices []*serviceDescription
|
||||
logger.Println(CollectionService)
|
||||
if err := mg.mongoClient.FindAllAs(CollectionService, bson.M{}, &allServices, options.Find().SetReturnKey(false)); err != nil {
|
||||
if err := mg.mongoClient.AllAs(CollectionService, &allServices, options.Find().SetReturnKey(false)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, service := range allServices {
|
||||
if err := service.prepare(mg); err != nil {
|
||||
if len(allServices) > 0 {
|
||||
only := allServices[0]
|
||||
only.prepare(mg)
|
||||
|
||||
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(only))
|
||||
} else {
|
||||
empty := serviceDescription{
|
||||
ServiceDescriptionSummary: ServiceDescriptionSummary{
|
||||
Id: primitive.NewObjectID(),
|
||||
},
|
||||
}
|
||||
|
||||
if *devflag {
|
||||
host, _ := os.Hostname()
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ipaddr := "127.0.0.1"
|
||||
for _, addr := range addrs {
|
||||
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
||||
if ipnet.IP.To4() != nil && ipnet.IP.IsPrivate() {
|
||||
ipaddr = ipnet.IP.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
empty.Divisions = map[string]*Division{
|
||||
host: {
|
||||
DivisionForUser: DivisionForUser{
|
||||
Priority: 0,
|
||||
State: DivisionState_FullOpen,
|
||||
LockCreateChar: false,
|
||||
},
|
||||
|
||||
Url: fmt.Sprintf("http://%s/warehouse", ipaddr),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
empty.prepare(mg)
|
||||
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(&empty))
|
||||
|
||||
filter := bson.M{"_id": empty.Id}
|
||||
_, _, err := mg.mongoClient.Update(CollectionService, filter, bson.M{
|
||||
"$set": &empty,
|
||||
}, options.Update().SetUpsert(true))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
logger.Println("RegisterHandlers...")
|
||||
|
||||
mg.services.init(allServices)
|
||||
for _, service := range allServices {
|
||||
if service.Closed {
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Println("ServiceCode:", service.ServiceCode)
|
||||
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, service.ServiceCode, "/"), service)
|
||||
}
|
||||
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "api", "/"), mg.api)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "query", "/"), mg.query)
|
||||
logger.Println("Service is registered :", mg.service().ServiceCode)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, mg.service().ServiceCode, "/"), func(w http.ResponseWriter, r *http.Request) {
|
||||
mg.service().serveHTTP(w, r)
|
||||
})
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "api/"), mg.api)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "query/"), mg.query)
|
||||
|
||||
configraw, _ := json.Marshal(mg.maingateConfig)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "config"), func(w http.ResponseWriter, r *http.Request) {
|
||||
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
||||
if len(apitoken) == 0 {
|
||||
logger.Println("MG-X-API-TOKEN is missing")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
var convertedConfig map[string]any
|
||||
if err := json.Unmarshal(configraw, &convertedConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "config"), func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
s := recover()
|
||||
if s != nil {
|
||||
logger.Error(s)
|
||||
}
|
||||
}()
|
||||
|
||||
if !*devflag {
|
||||
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
||||
if len(apitoken) == 0 {
|
||||
logger.Println("MG-X-API-TOKEN is missing")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
apitokenObj, _ := primitive.ObjectIDFromHex(apitoken)
|
||||
if mg.service().isValidToken(apitokenObj) {
|
||||
convertedConfig["divisions"] = mg.service().Divisions
|
||||
}
|
||||
} else {
|
||||
convertedConfig["divisions"] = mg.service().Divisions
|
||||
}
|
||||
|
||||
_, exists := mg.apiTokenToService.get(apitoken)
|
||||
if !exists {
|
||||
logger.Println("MG-X-API-TOKEN is invalid :", apitoken)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(configraw)
|
||||
enc := json.NewEncoder(w)
|
||||
enc.Encode(convertedConfig)
|
||||
})
|
||||
|
||||
fsx := http.FileServer(http.Dir("./console"))
|
||||
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, "console", "/"), http.StripPrefix("/console/", fsx))
|
||||
if err := os.MkdirAll("static", os.ModePerm); err != nil {
|
||||
// 일반 엔드유저한테 오픈할 static 페이지
|
||||
return err
|
||||
}
|
||||
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformGoogle), mg.platform_google_get_login_url)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformGoogle), mg.platform_google_authorize)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformGoogle), mg.platform_google_authorize_result)
|
||||
cfsx := http.FileServer(http.Dir("console"))
|
||||
pattern := gocommon.MakeHttpHandlerPattern(prefix, "console", "/")
|
||||
serveMux.Handle(pattern, http.StripPrefix(pattern, cfsx))
|
||||
logger.Println("maingate console registered :", pattern)
|
||||
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformMicrosoft), mg.platform_microsoft_get_login_url)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformMicrosoft), mg.platform_microsoft_authorize)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformMicrosoft), mg.platform_microsoft_authorize_result)
|
||||
staticfs := http.FileServer(http.Dir("static"))
|
||||
pattern = gocommon.MakeHttpHandlerPattern(prefix, "static", "/")
|
||||
serveMux.Handle(pattern, http.StripPrefix(pattern, staticfs))
|
||||
logger.Println("maingate static registered :", pattern)
|
||||
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformTwitter), mg.platform_twitter_get_login_url)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformTwitter), mg.platform_twitter_authorize)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformTwitter), mg.platform_twitter_authorize_result)
|
||||
fbafs := http.FileServer(http.Dir("fba"))
|
||||
pattern = gocommon.MakeHttpHandlerPattern(prefix, "fba", "/")
|
||||
serveMux.Handle(pattern, http.StripPrefix(pattern, fbafs))
|
||||
logger.Println("google_analytics static registered :", pattern)
|
||||
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformApple), mg.platform_apple_get_login_url)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformApple), mg.platform_apple_authorize)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformApple), mg.platform_apple_authorize_result)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "fba", "fb-ga.min.js"), mg.google_analytics_js)
|
||||
logger.Println("google_analytics.js static registered :", pattern)
|
||||
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformGamepot), mg.platform_gamepot_get_login_url)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformGamepot), mg.platform_gamepot_authorize)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize_sdk", AuthPlatformGamepot), mg.platform_gamepot_authorize_sdk)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformGoogle), mg.platform_google_get_login_url)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformGoogle), mg.platform_google_authorize)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformGoogle), mg.platform_google_authorize_result)
|
||||
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformFirebaseAuth), mg.platform_firebaseauth_get_login_url)
|
||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize_sdk", AuthPlatformFirebaseAuth), mg.platform_firebaseauth_authorize_sdk)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformMicrosoft), mg.platform_microsoft_get_login_url)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformMicrosoft), mg.platform_microsoft_authorize)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformMicrosoft), mg.platform_microsoft_authorize_result)
|
||||
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformTwitter), mg.platform_twitter_get_login_url)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformTwitter), mg.platform_twitter_authorize)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformTwitter), mg.platform_twitter_authorize_result)
|
||||
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformApple), mg.platform_apple_get_login_url)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformApple), mg.platform_apple_authorize)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformApple), mg.platform_apple_authorize_result)
|
||||
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformFirebaseAuth), mg.platform_firebaseauth_get_login_url)
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_sdk", AuthPlatformFirebaseAuth), mg.platform_firebaseauth_authorize_sdk)
|
||||
|
||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_sdk", AuthPlatformSteamSDK), mg.platform_steamsdk_authorize)
|
||||
|
||||
go mg.watchServiceCollection(ctx, serveMux, prefix)
|
||||
|
||||
go mg.watchFileCollection(ctx, serveMux, prefix)
|
||||
// fsx := http.FileServer(http.Dir("console"))
|
||||
// serveMux.Handle("/console/", http.StripPrefix("/console/", fsx))
|
||||
// logger.Println("console file server open")
|
||||
@ -607,24 +636,20 @@ func (mg *Maingate) query(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
||||
if len(apitoken) == 0 {
|
||||
logger.Println("MG-X-API-TOKEN is missing")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if !*devflag {
|
||||
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
||||
if len(apitoken) == 0 {
|
||||
logger.Println("MG-X-API-TOKEN is missing")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
servicecode, exists := mg.apiTokenToService.get(apitoken)
|
||||
if !exists {
|
||||
logger.Println("MG-X-API-TOKEN is invalid :", apitoken)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if info.ServiceCode != servicecode {
|
||||
logger.Println("session is not for this service :", info.ServiceCode, servicecode)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
apitokenObj, _ := primitive.ObjectIDFromHex(apitoken)
|
||||
if !mg.service().isValidToken(apitokenObj) {
|
||||
logger.Println("MG-X-API-TOKEN is invalid :", apitoken)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
bt, _ := json.Marshal(info)
|
||||
@ -642,32 +667,27 @@ func (mg *Maingate) GeneratePlatformLoginNonceKey() string {
|
||||
|
||||
func (mg *Maingate) GetUserBrowserInfo(r *http.Request) (string, error) {
|
||||
//=========== 브라우저 검증쪽은 앞으로 빼자
|
||||
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
logger.Error("Error: RemoteAddr Split Error :", err)
|
||||
}
|
||||
// host, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
// if err != nil {
|
||||
// logger.Error("Error: RemoteAddr Split Error :", err)
|
||||
// }
|
||||
|
||||
cookie, err := r.Cookie("ActionSquareSessionExtraInfo")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestinfo := fmt.Sprintf("%s_%s", cookie.Value, host)
|
||||
//requestinfo := fmt.Sprintf("%s_%s", cookie.Value, host) //-- RemoteAddr체크는 로드밸런서 IP 찍히는 문제 때문에 제외한다.
|
||||
requestinfo := fmt.Sprintf("%s_", cookie.Value)
|
||||
return requestinfo, nil
|
||||
}
|
||||
|
||||
func (mg *Maingate) setUserToken(info usertokeninfo) error {
|
||||
|
||||
mg.mongoClient.Delete(CollectionUserToken, bson.M{
|
||||
_, _, err := mg.mongoClient.Update(CollectionUserToken, bson.M{
|
||||
"platform": info.platform,
|
||||
"userid": info.userid,
|
||||
})
|
||||
_, _, err := mg.mongoClient.Update(CollectionUserToken, bson.M{
|
||||
"_id": primitive.NewObjectID(),
|
||||
}, bson.M{
|
||||
"$setOnInsert": bson.M{
|
||||
"platform": info.platform,
|
||||
"userid": info.userid,
|
||||
"$set": bson.M{
|
||||
"token": info.token,
|
||||
"secret": info.secret,
|
||||
"brinfo": info.brinfo,
|
||||
@ -686,14 +706,17 @@ func (mg *Maingate) getUserTokenWithCheck(platform string, userid string, brinfo
|
||||
found, err := mg.mongoClient.FindOne(CollectionUserToken, bson.M{
|
||||
"platform": platform,
|
||||
"userid": userid,
|
||||
"brinfo": brinfo,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return info, err
|
||||
}
|
||||
if found == nil {
|
||||
return info, errors.New("user token not found: " + platform + " / " + userid + " / " + brinfo)
|
||||
return info, errors.New("user token not found :" + platform + " / " + userid + " / " + brinfo)
|
||||
}
|
||||
|
||||
if found["brinfo"].(string) != brinfo {
|
||||
return info, errors.New("user brinfo is different :" + platform + " / " + userid + " / " + brinfo)
|
||||
}
|
||||
|
||||
updatetime, ok := found["lastupdate"].(int64)
|
||||
@ -745,8 +768,8 @@ func (mg *Maingate) updateUserinfo(info usertokeninfo) (bool, string, string) {
|
||||
success, userid, email = mg.platform_microsoft_getuserinfo(info)
|
||||
case AuthPlatformGoogle:
|
||||
success, userid, email = mg.platform_google_getuserinfo(info)
|
||||
case AuthPlatformGamepot:
|
||||
success, userid, email = mg.platform_gamepot_getuserinfo(info)
|
||||
case AuthPlatformSteamSDK:
|
||||
success, userid, email = mg.platform_steamsdk_getuserinfo(info)
|
||||
case AuthPlatformFirebaseAuth:
|
||||
success, userid, email = mg.platform_firebase_getuserinfo(info)
|
||||
}
|
||||
@ -766,7 +789,7 @@ func (mg *Maingate) updateUserinfo(info usertokeninfo) (bool, string, string) {
|
||||
|
||||
}
|
||||
|
||||
func (mg *Maingate) getProviderInfo(platform string, uid string) (error, string, string) {
|
||||
func (mg *Maingate) getProviderInfo(platform string, uid string) (string, string, error) {
|
||||
provider := ""
|
||||
providerid := ""
|
||||
|
||||
@ -777,26 +800,31 @@ func (mg *Maingate) getProviderInfo(platform string, uid string) (error, string,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err, "", ""
|
||||
return "", "", err
|
||||
}
|
||||
if found == nil {
|
||||
return errors.New("firebase info not found: " + uid), "", ""
|
||||
return "", "", errors.New("firebase info not found: " + uid)
|
||||
}
|
||||
provider = found["firebaseprovider"].(string)
|
||||
providerid = found["firebaseproviderId"].(string)
|
||||
if provider == "" || providerid == "" {
|
||||
return errors.New("getProviderInfo - firebase info not found: " + provider + " / " + providerid), "", ""
|
||||
return "", "", errors.New("getProviderInfo - firebase info not found: " + provider + " / " + providerid)
|
||||
}
|
||||
case "":
|
||||
//guest auth
|
||||
providerid = uid
|
||||
if providerid == "" {
|
||||
return "", "", errors.New("getProviderInfo - guest provider id not found: " + provider + " / " + providerid)
|
||||
}
|
||||
default:
|
||||
provider = platform
|
||||
providerid = uid
|
||||
if provider == "" || providerid == "" {
|
||||
return "", "", errors.New("getProviderInfo - provider info not found: " + provider + " / " + providerid)
|
||||
}
|
||||
}
|
||||
|
||||
if provider == "" || providerid == "" {
|
||||
return errors.New("getProviderInfo - provider info not found: " + provider + " / " + providerid), "", ""
|
||||
}
|
||||
|
||||
return nil, provider, providerid
|
||||
return provider, providerid, nil
|
||||
|
||||
}
|
||||
|
||||
@ -956,3 +984,31 @@ func JWTparseCode(keyurl string, code string) (string, string, string) {
|
||||
//--- nonce 체크 필요하다.
|
||||
return claims["sub"].(string), email, nonce
|
||||
}
|
||||
|
||||
func (mg *Maingate) google_analytics_html(w http.ResponseWriter, r *http.Request) {
|
||||
parsedTemplate, _ := template.ParseFiles("template/track-event.html")
|
||||
err := parsedTemplate.Execute(w, nil)
|
||||
if err != nil {
|
||||
logger.Error("Error executing template :", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (mg *Maingate) google_analytics_js(w http.ResponseWriter, r *http.Request) {
|
||||
fgaconfig := Firebase_Google_Analytics_JS_SDK_Config{
|
||||
FGA_apiKey: mg.FGA_apiKey,
|
||||
FGA_authDomain: mg.FGA_authDomain,
|
||||
FGA_databaseURL: mg.FGA_databaseURL,
|
||||
FGA_projectId: mg.FGA_projectId,
|
||||
FGA_storageBucket: mg.FGA_storageBucket,
|
||||
FGA_messagingSenderId: mg.FGA_messagingSenderId,
|
||||
FGA_appId: mg.FGA_appId,
|
||||
FGA_measurementId: mg.FGA_measurementId,
|
||||
}
|
||||
parsedTemplate, _ := template.ParseFiles("template/fb-ga.min.js")
|
||||
err := parsedTemplate.Execute(w, fgaconfig)
|
||||
if err != nil {
|
||||
logger.Error("Error executing template :", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
177
core/member_container.go
Normal file
177
core/member_container.go
Normal file
@ -0,0 +1,177 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"repositories.action2quare.com/ayo/gocommon"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
)
|
||||
|
||||
type memberContraints[K comparable] interface {
|
||||
Key() K
|
||||
Expired() bool
|
||||
}
|
||||
|
||||
type memberContainerPtr[K comparable, T memberContraints[K]] struct {
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func (p *memberContainerPtr[K, T]) init(ms []T) {
|
||||
next := map[K]T{}
|
||||
for _, m := range ms {
|
||||
next[m.Key()] = m
|
||||
}
|
||||
atomic.StorePointer(&p.ptr, unsafe.Pointer(&next))
|
||||
}
|
||||
|
||||
func (p *memberContainerPtr[K, T]) add(m T) {
|
||||
ptr := atomic.LoadPointer(&p.ptr)
|
||||
src := (*map[K]T)(ptr)
|
||||
|
||||
next := map[K]T{}
|
||||
for k, v := range *src {
|
||||
next[k] = v
|
||||
}
|
||||
next[m.Key()] = m
|
||||
atomic.StorePointer(&p.ptr, unsafe.Pointer(&next))
|
||||
}
|
||||
|
||||
func (p *memberContainerPtr[K, T]) get(key K) (T, bool) {
|
||||
ptr := atomic.LoadPointer(&p.ptr)
|
||||
src := (*map[K]T)(ptr)
|
||||
|
||||
out, found := (*src)[key]
|
||||
return out, found
|
||||
}
|
||||
|
||||
func (p *memberContainerPtr[K, T]) remove(key K) {
|
||||
ptr := atomic.LoadPointer(&p.ptr)
|
||||
src := (*map[K]T)(ptr)
|
||||
|
||||
next := map[K]T{}
|
||||
for k, v := range *src {
|
||||
next[k] = v
|
||||
}
|
||||
delete(next, key)
|
||||
atomic.StorePointer(&p.ptr, unsafe.Pointer(&next))
|
||||
}
|
||||
|
||||
type memberPipelineDocument[K comparable, T memberContraints[K]] struct {
|
||||
OperationType string `bson:"operationType"`
|
||||
DocumentKey struct {
|
||||
Id primitive.ObjectID `bson:"_id"`
|
||||
} `bson:"documentKey"`
|
||||
Member T `bson:"fullDocument"`
|
||||
}
|
||||
|
||||
func (p *memberContainerPtr[K, T]) all() []T {
|
||||
ptr := atomic.LoadPointer(&p.ptr)
|
||||
src := (*map[K]T)(ptr)
|
||||
|
||||
out := make([]T, 0, len(*src))
|
||||
for _, m := range *src {
|
||||
if m.Expired() {
|
||||
continue
|
||||
}
|
||||
out = append(out, m)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (p *memberContainerPtr[K, T]) contains(key K, out *T) bool {
|
||||
ptr := atomic.LoadPointer(&p.ptr)
|
||||
src := (*map[K]T)(ptr)
|
||||
|
||||
found, exists := (*src)[key]
|
||||
if exists {
|
||||
if found.Expired() {
|
||||
p.remove(key)
|
||||
return false
|
||||
}
|
||||
if out != nil {
|
||||
*out = found
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *memberContainerPtr[K, T]) watchCollection(parentctx context.Context, coll gocommon.CollectionName, mc gocommon.MongoClient) {
|
||||
defer func() {
|
||||
s := recover()
|
||||
if s != nil {
|
||||
logger.Error(s)
|
||||
}
|
||||
}()
|
||||
|
||||
matchStage := bson.D{
|
||||
{
|
||||
Key: "$match", Value: bson.D{
|
||||
{Key: "operationType", Value: bson.D{
|
||||
{Key: "$in", Value: bson.A{
|
||||
"update",
|
||||
"insert",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
}}
|
||||
projectStage := bson.D{
|
||||
{
|
||||
Key: "$project", Value: bson.D{
|
||||
{Key: "documentKey", Value: 1},
|
||||
{Key: "fullDocument", Value: 1},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var stream *mongo.ChangeStream
|
||||
var err error
|
||||
var ctx context.Context
|
||||
|
||||
for {
|
||||
if stream == nil {
|
||||
stream, err = mc.Watch(coll, mongo.Pipeline{matchStage, projectStage})
|
||||
if err != nil {
|
||||
logger.Error("watchCollection watch failed :", err)
|
||||
time.Sleep(time.Minute)
|
||||
continue
|
||||
}
|
||||
ctx = context.TODO()
|
||||
}
|
||||
|
||||
changed := stream.TryNext(ctx)
|
||||
if ctx.Err() != nil {
|
||||
logger.Error("watchCollection stream.TryNext failed. process should be restarted! :", ctx.Err().Error())
|
||||
break
|
||||
}
|
||||
|
||||
if changed {
|
||||
var data memberPipelineDocument[K, T]
|
||||
if err := stream.Decode(&data); err == nil {
|
||||
p.add(data.Member)
|
||||
} else {
|
||||
logger.Error("watchCollection stream.Decode failed :", err)
|
||||
}
|
||||
} else if stream.Err() != nil || stream.ID() == 0 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
logger.Println("watchCollection is done")
|
||||
stream.Close(ctx)
|
||||
return
|
||||
|
||||
case <-time.After(time.Second):
|
||||
logger.Error("watchCollection stream error :", stream.Err())
|
||||
stream.Close(ctx)
|
||||
stream = nil
|
||||
}
|
||||
} else {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/logger"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
|
||||
"github.com/golang-jwt/jwt"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
@ -289,7 +289,7 @@ func (mg *Maingate) platform_apple_getuserinfo(refreshToken string) (bool, strin
|
||||
}
|
||||
|
||||
if respReferesh.Error != "" {
|
||||
logger.Error("apple returned an error: %s - %s\n", respReferesh.Error, respReferesh.ErrorDescription)
|
||||
logger.Errorf("apple returned an error: %s - %s\n", respReferesh.Error, respReferesh.ErrorDescription)
|
||||
return false, "", ""
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/logger"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
|
||||
@ -1,344 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/logger"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
type GamepotTemplate struct {
|
||||
RedirectBaseUrl string
|
||||
State string
|
||||
}
|
||||
|
||||
type Gamepot_LoginValidationResponse struct {
|
||||
Message string `json:"message"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
func (mg *Maingate) platform_gamepot_get_login_url(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
browserinfo, err := mg.GetUserBrowserInfo(r)
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
existid := r.URL.Query().Get("existid")
|
||||
withSDK := r.URL.Query().Get("withSDK")
|
||||
|
||||
//fmt.Println("existid =>", existid)
|
||||
if existid != "" {
|
||||
//기존 계정이 있는 경우에는 그 계정 부터 조회한다.
|
||||
info, err := mg.getUserTokenWithCheck(AuthPlatformGamepot, existid, browserinfo)
|
||||
if err == nil {
|
||||
if info.token != "" {
|
||||
params := url.Values{}
|
||||
params.Add("id", existid)
|
||||
params.Add("authtype", AuthPlatformGamepot)
|
||||
if withSDK == "1" {
|
||||
w.Write([]byte("?" + params.Encode()))
|
||||
} else {
|
||||
http.Redirect(w, r, "actionsquare://login?"+params.Encode(), http.StatusSeeOther)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sessionkey := mg.GeneratePlatformLoginNonceKey()
|
||||
nonce := mg.GeneratePlatformLoginNonceKey()
|
||||
|
||||
mg.mongoClient.Delete(CollectionPlatformLoginToken, bson.M{
|
||||
"platform": AuthPlatformGamepot,
|
||||
"key": sessionkey,
|
||||
})
|
||||
|
||||
_, _, err = mg.mongoClient.Update(CollectionPlatformLoginToken, bson.M{
|
||||
"_id": primitive.NewObjectID(),
|
||||
}, bson.M{
|
||||
"$setOnInsert": bson.M{
|
||||
"platform": AuthPlatformGamepot,
|
||||
"key": sessionkey,
|
||||
"nonce": nonce,
|
||||
"brinfo": browserinfo,
|
||||
},
|
||||
}, options.Update().SetUpsert(true))
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// set cookie for storing token
|
||||
cookie := http.Cookie{
|
||||
Name: "LoginFlowContext_SessionKey",
|
||||
Value: sessionkey,
|
||||
Expires: time.Now().Add(1 * time.Hour),
|
||||
//SameSite: http.SameSiteStrictMode,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
// HttpOnly: false,
|
||||
Secure: true,
|
||||
Path: "/",
|
||||
}
|
||||
http.SetCookie(w, &cookie)
|
||||
|
||||
if withSDK == "1" {
|
||||
params := url.Values{}
|
||||
params.Add("nonce", nonce)
|
||||
w.Write([]byte("?" + params.Encode()))
|
||||
} else {
|
||||
var templateVar GamepotTemplate
|
||||
templateVar.RedirectBaseUrl = mg.RedirectBaseUrl
|
||||
templateVar.State = nonce
|
||||
mg.webTemplate[AuthPlatformGamepot].Execute(w, templateVar)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (mg *Maingate) platform_gamepot_authorize(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
|
||||
brinfo, err := mg.GetUserBrowserInfo(r)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
cookie, err := r.Cookie("LoginFlowContext_SessionKey")
|
||||
if err != nil {
|
||||
logger.Println("Session not found", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
r.ParseForm()
|
||||
|
||||
code := r.Form.Get("code")
|
||||
state := r.Form.Get("state")
|
||||
|
||||
gamepotmemberId := r.Form.Get("id")
|
||||
gamepotnickname := r.Form.Get("nickname")
|
||||
gamepotprovider := r.Form.Get("provider")
|
||||
gamepotproviderId := r.Form.Get("providerId")
|
||||
// gamepotverify := r.Form.Get("verify")
|
||||
// gamepotagree := r.Form.Get("agree")
|
||||
|
||||
bSuccess, Result := mg.platform_gamepot_authorize_raw(w, brinfo, code, state, cookie.Value, gamepotmemberId, gamepotnickname, gamepotprovider, gamepotproviderId)
|
||||
|
||||
if bSuccess {
|
||||
http.Redirect(w, r, "actionsquare://login?"+Result, http.StatusSeeOther)
|
||||
} else {
|
||||
http.Redirect(w, r, "actionsquare://error", http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
|
||||
type GamePotSDKAuthInfo struct {
|
||||
Code string `json:"code"`
|
||||
State string `json:"state"`
|
||||
MemberId string `json:"id"`
|
||||
Nickname string `json:"nickname"`
|
||||
Provider string `json:"provider"`
|
||||
ProviderId string `json:"providerId"`
|
||||
// Verify string `json:"verify"`
|
||||
// Agree string `json:"agree"`
|
||||
}
|
||||
|
||||
func (mg *Maingate) platform_gamepot_authorize_sdk(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
defer r.Body.Close()
|
||||
|
||||
brinfo, err := mg.GetUserBrowserInfo(r)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
cookie, err := r.Cookie("LoginFlowContext_SessionKey")
|
||||
if err != nil {
|
||||
logger.Println("Session not found", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var authinfo GamePotSDKAuthInfo
|
||||
|
||||
err = json.NewDecoder(r.Body).Decode(&authinfo)
|
||||
if err != nil {
|
||||
logger.Println("authinfo decoding fail:", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
bSuccess, Result := mg.platform_gamepot_authorize_raw(w, brinfo, authinfo.Code, authinfo.State,
|
||||
cookie.Value, authinfo.MemberId, authinfo.Nickname, authinfo.Provider, authinfo.ProviderId)
|
||||
|
||||
if bSuccess {
|
||||
w.Write([]byte("?" + Result))
|
||||
//http.Redirect(w, r, "actionsquare://login?"+Result, http.StatusSeeOther)
|
||||
} else {
|
||||
http.Redirect(w, r, "actionsquare://error", http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
|
||||
func (mg *Maingate) platform_gamepot_authorize_raw(w http.ResponseWriter, brinfo, code, state, cookieSessionKey, gamepotmemberId, gamepotnickname, gamepotprovider, gamepotproviderId string) (bool, string) {
|
||||
|
||||
found, err := mg.mongoClient.FindOne(CollectionPlatformLoginToken, bson.M{
|
||||
"platform": AuthPlatformGamepot,
|
||||
"key": cookieSessionKey,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logger.Println("LoginFlowContext_SessionKey find key :", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
if found == nil {
|
||||
logger.Println("LoginFlowContext_SessionKey not found")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
if cookieSessionKey != found["key"] {
|
||||
logger.Println("LoginFlowContext_SessionKey key not match")
|
||||
logger.Println(cookieSessionKey)
|
||||
logger.Println(found["key"])
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
if state != found["nonce"] {
|
||||
logger.Println("LoginFlowContext_SessionKey nonce not match")
|
||||
logger.Println(state)
|
||||
logger.Println(found["nonce"])
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
if brinfo != found["brinfo"] { //-- 로그인 시작점과 인증점의 브라우저 혹은 접속지 정보가 다르다?
|
||||
logger.Println("LoginFlowContext_SessionKey brinfo not match ")
|
||||
logger.Println(brinfo)
|
||||
logger.Println(found["brinfo"])
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
//=================
|
||||
params := url.Values{}
|
||||
params.Add("projectId", mg.GamepotProjectId)
|
||||
params.Add("memberId", gamepotmemberId)
|
||||
params.Add("token", code)
|
||||
|
||||
var respLoginCheck Gamepot_LoginValidationResponse
|
||||
content := params.Encode()
|
||||
resp, _ := http.Post(mg.GamepotLoginCheckAPIURL, "application/json", bytes.NewBuffer([]byte(content)))
|
||||
if resp != nil {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
json.Unmarshal(body, &respLoginCheck)
|
||||
} else {
|
||||
logger.Println("gamepot logincheck fail.")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// fmt.Println("==============================")
|
||||
// fmt.Println("respLoginCheck.Status:", respLoginCheck.Status)
|
||||
// fmt.Println("respLoginCheck.Message:", respLoginCheck.Message)
|
||||
// fmt.Println("==============================")
|
||||
|
||||
if respLoginCheck.Status != 0 {
|
||||
logger.Errorf("gamepot login fail:", respLoginCheck.Message)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
acceestoken_expire_time := time.Date(2999, 1, int(time.January), 0, 0, 0, 0, time.UTC).Unix()
|
||||
|
||||
if gamepotmemberId != "" && gamepotprovider != "" && gamepotproviderId != "" {
|
||||
var info usertokeninfo
|
||||
info.platform = AuthPlatformGamepot
|
||||
info.userid = gamepotmemberId
|
||||
//== memberid 제외하고는 모두 client로 부터 온 값이기 때문에 유효성이 확인된 값이 아니다. 하지만, 참조용으로 사용은 한다.
|
||||
// 정확한 정보는 gamepotid를 gamepot dashboard에서 조회해서 확인 할 수 밖에 없다.
|
||||
info.token = gamepotprovider + "-" + gamepotproviderId
|
||||
info.brinfo = brinfo
|
||||
info.accesstoken = ""
|
||||
info.accesstoken_expire_time = acceestoken_expire_time
|
||||
mg.setUserToken(info)
|
||||
|
||||
mg.mongoClient.Delete(CollectionGamepotUserInfo, bson.M{
|
||||
"gamepotuserid": info.userid,
|
||||
})
|
||||
|
||||
_, _, err := mg.mongoClient.Update(CollectionGamepotUserInfo, bson.M{
|
||||
"_id": primitive.NewObjectID(),
|
||||
}, bson.M{
|
||||
"$setOnInsert": bson.M{
|
||||
"gamepotuserid": gamepotmemberId,
|
||||
"gamepotnickname": gamepotnickname,
|
||||
"gamepotprovider": gamepotprovider,
|
||||
"gamepotproviderId": gamepotproviderId,
|
||||
// "gamepotverify": gamepotverify,
|
||||
// "gamepotagree": gamepotagree,
|
||||
"updatetime": time.Now(),
|
||||
},
|
||||
}, options.Update().SetUpsert(true))
|
||||
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
|
||||
params := url.Values{}
|
||||
params.Add("id", gamepotmemberId)
|
||||
params.Add("authtype", AuthPlatformGamepot)
|
||||
return true, params.Encode()
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func (mg *Maingate) platform_gamepot_getuserinfo(info usertokeninfo) (bool, string, string) {
|
||||
|
||||
found, err := mg.mongoClient.FindOne(CollectionGamepotUserInfo, bson.M{
|
||||
"gamepotuserid": info.userid,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return false, "", ""
|
||||
}
|
||||
if found == nil {
|
||||
logger.Error(errors.New("gamepot info not found: " + info.userid))
|
||||
return false, "", ""
|
||||
}
|
||||
|
||||
gamepotprovider := found["gamepotprovider"].(string)
|
||||
gamepotproviderId := found["gamepotproviderId"].(string)
|
||||
|
||||
if gamepotprovider+"-"+gamepotproviderId != info.token {
|
||||
logger.Println("gamepot info not match..") //-- token은 플랫폼종류+플랫폼ID로 구성했는데... 검증할 방법이 없어서 client로 부터 온값을 쓴다. 그래도 유저가 조작하지 않는 이상 일치해야 된다.
|
||||
logger.Println(info.token)
|
||||
logger.Println(gamepotprovider + "-" + gamepotproviderId)
|
||||
return false, "", ""
|
||||
}
|
||||
|
||||
tempEmail := info.userid + "@gamepot" //-- 게임팟은 email을 안줘서 일단 gamepotid기준으로 임시값을 할당한다.
|
||||
|
||||
return true, info.userid, tempEmail
|
||||
|
||||
}
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/logger"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/logger"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
|
||||
126
core/platformsteam.go
Normal file
126
core/platformsteam.go
Normal file
@ -0,0 +1,126 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
)
|
||||
|
||||
type SteamSDKAuthInfo struct {
|
||||
UserSteamId string `json:"steamid"`
|
||||
UserAuthToken string `json:"authtoken"`
|
||||
}
|
||||
|
||||
func (mg *Maingate) platform_steamsdk_authorize(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
defer r.Body.Close()
|
||||
|
||||
brinfo, err := mg.GetUserBrowserInfo(r)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
var authinfo SteamSDKAuthInfo
|
||||
|
||||
err = json.NewDecoder(r.Body).Decode(&authinfo)
|
||||
if err != nil {
|
||||
logger.Println("authinfo decoding fail:", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if !*noauth {
|
||||
err = authenticateSteamUser(mg.SteamPublisherAuthKey, mg.SteamAppId, authinfo.UserSteamId, authinfo.UserAuthToken)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
acceestoken_expire_time := time.Date(2999, 1, int(time.January), 0, 0, 0, 0, time.UTC).Unix()
|
||||
|
||||
var info usertokeninfo
|
||||
info.platform = AuthPlatformSteamSDK
|
||||
info.userid = authinfo.UserSteamId
|
||||
info.token = authinfo.UserAuthToken
|
||||
info.brinfo = brinfo
|
||||
//info.accesstoken = respReferesh.AccessToken
|
||||
info.accesstoken_expire_time = acceestoken_expire_time
|
||||
mg.setUserToken(info)
|
||||
|
||||
params := url.Values{}
|
||||
params.Add("id", authinfo.UserSteamId)
|
||||
params.Add("authtype", AuthPlatformSteamSDK)
|
||||
w.Write([]byte("?" + params.Encode()))
|
||||
//http.Redirect(w, r, "actionsquare://login?"+Result, http.StatusSeeOther)
|
||||
} else {
|
||||
logger.Println(err)
|
||||
http.Redirect(w, r, "actionsquare://error", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func authenticateSteamUser(pubkey, appid, playerid, ticket string) error {
|
||||
// Returns: The user's 64-bit SteamID if the user's ticket is valid
|
||||
url := fmt.Sprintf("https://partner.steam-api.com/ISteamUserAuth/AuthenticateUserTicket/v1/?key=%s&appid=%s&ticket=%s", pubkey, appid, ticket)
|
||||
resp, e := http.Get(url)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer func() {
|
||||
io.Copy(io.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
}()
|
||||
|
||||
body, e := ioutil.ReadAll(resp.Body)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
// fmt.Println(url)
|
||||
// fmt.Println(string(body))
|
||||
|
||||
var doc map[string]interface{}
|
||||
if err := json.Unmarshal(body, &doc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v, ok := doc["response"]; ok {
|
||||
response := v.(map[string]interface{})
|
||||
if v, ok = response["params"]; ok {
|
||||
paramsnode := v.(map[string]interface{})
|
||||
if v, ok = paramsnode["result"]; ok {
|
||||
if v.(string) == "OK" {
|
||||
if v, ok = paramsnode["steamid"]; ok {
|
||||
// playerid에는 빌드 구성 suffix가 붙어있는 상태이므로 == 비교가 아니라 HasPrefix로 비교
|
||||
if strings.HasPrefix(playerid, v.(string)) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else if v.(string) == "Invalid ticket" {
|
||||
return errors.New("steam: invalid ticket")
|
||||
}
|
||||
}
|
||||
} else if errdocraw, ok := response["error"]; ok {
|
||||
errdoc := errdocraw.(map[string]interface{})
|
||||
desc := errdoc["errordesc"].(string)
|
||||
return errors.New(desc)
|
||||
}
|
||||
}
|
||||
return errors.New("steam: response is not expected")
|
||||
}
|
||||
|
||||
func (mg *Maingate) platform_steamsdk_getuserinfo(info usertokeninfo) (bool, string, string) {
|
||||
|
||||
// Steam은 이메일 정보를 받을수 없기 때문에 dummy임시 주소 할당하여 리턴한다.
|
||||
dummyEmail := fmt.Sprintf("__dummy_%s@steamtemp__", info.userid)
|
||||
return true, info.userid, dummyEmail
|
||||
|
||||
}
|
||||
@ -12,7 +12,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/logger"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
@ -222,14 +222,13 @@ func (mg *Maingate) platform_twitter_authorize_result(w http.ResponseWriter, r *
|
||||
|
||||
func (mg *Maingate) platform_twitter_getuserinfo(token, secret string) (bool, string, string) {
|
||||
|
||||
result := mg.CallTwitterAPI("https://api.twitter.com/2/users/me", "GET", token, secret, mg.GeneratePlatformLoginNonceKey())
|
||||
result := mg.CallTwitterAPI("https://api.twitter.com/1.1/account/verify_credentials.json?include_email=true", "GET", token, secret, mg.GeneratePlatformLoginNonceKey())
|
||||
|
||||
var TwitterUserInfo struct {
|
||||
Data struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
} `json:"data"`
|
||||
Id string `json:"id_str"`
|
||||
Name string `json:"name"`
|
||||
Username string `json:"screen_name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(result), &TwitterUserInfo)
|
||||
@ -240,12 +239,13 @@ func (mg *Maingate) platform_twitter_getuserinfo(token, secret string) (bool, st
|
||||
|
||||
// fmt.Println("=====================")
|
||||
// fmt.Println(result)
|
||||
// fmt.Println(TwitterUserInfo.Data.Id)
|
||||
// fmt.Println(TwitterUserInfo.Data.Name)
|
||||
// fmt.Println(TwitterUserInfo.Data.Username)
|
||||
// fmt.Println(TwitterUserInfo.Id)
|
||||
// fmt.Println(TwitterUserInfo.Name)
|
||||
// fmt.Println(TwitterUserInfo.Username)
|
||||
// fmt.Println(TwitterUserInfo.Email)
|
||||
// fmt.Println("=====================")
|
||||
|
||||
return true, TwitterUserInfo.Data.Id, ""
|
||||
return true, TwitterUserInfo.Id, TwitterUserInfo.Email
|
||||
}
|
||||
|
||||
func (mg *Maingate) CallTwitterAPI_WithAPPKey(requesturl, method, nonce string) string {
|
||||
|
||||
870
core/service.go
870
core/service.go
File diff suppressed because it is too large
Load Diff
170
core/watch.go
170
core/watch.go
@ -2,13 +2,16 @@ package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/logger"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/common"
|
||||
"repositories.action2quare.com/ayo/gocommon"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
@ -21,7 +24,7 @@ type authPipelineDocument struct {
|
||||
DocumentKey struct {
|
||||
Id primitive.ObjectID `bson:"_id"`
|
||||
} `bson:"documentKey"`
|
||||
Authinfo *common.Authinfo `bson:"fullDocument"`
|
||||
Authinfo *gocommon.Authinfo `bson:"fullDocument"`
|
||||
}
|
||||
|
||||
type servicePipelineDocument struct {
|
||||
@ -32,15 +35,15 @@ type servicePipelineDocument struct {
|
||||
Service *serviceDescription `bson:"fullDocument"`
|
||||
}
|
||||
|
||||
type whilelistPipelineDocument struct {
|
||||
type filePipelineDocument struct {
|
||||
OperationType string `bson:"operationType"`
|
||||
DocumentKey struct {
|
||||
Id primitive.ObjectID `bson:"_id"`
|
||||
} `bson:"documentKey"`
|
||||
Member *whitelistmember `bson:"fullDocument"`
|
||||
File *FileDocumentDesc `bson:"fullDocument"`
|
||||
}
|
||||
|
||||
func (mg *Maingate) watchWhitelistCollection(parentctx context.Context) {
|
||||
func (mg *Maingate) watchFileCollection(parentctx context.Context, serveMux *http.ServeMux, prefix string) {
|
||||
defer func() {
|
||||
s := recover()
|
||||
if s != nil {
|
||||
@ -53,7 +56,7 @@ func (mg *Maingate) watchWhitelistCollection(parentctx context.Context) {
|
||||
Key: "$match", Value: bson.D{
|
||||
{Key: "operationType", Value: bson.D{
|
||||
{Key: "$in", Value: bson.A{
|
||||
"update",
|
||||
"delete",
|
||||
"insert",
|
||||
}},
|
||||
}},
|
||||
@ -62,23 +65,22 @@ func (mg *Maingate) watchWhitelistCollection(parentctx context.Context) {
|
||||
projectStage := bson.D{
|
||||
{
|
||||
Key: "$project", Value: bson.D{
|
||||
{Key: "documentKey", Value: 1},
|
||||
{Key: "operationType", Value: 1},
|
||||
{Key: "documentKey", Value: 1},
|
||||
{Key: "fullDocument", Value: 1},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var stream *mongo.ChangeStream
|
||||
var err error
|
||||
var ctx context.Context
|
||||
|
||||
for {
|
||||
if stream == nil {
|
||||
stream, err = mg.mongoClient.Watch(CollectionWhitelist, mongo.Pipeline{matchStage, projectStage})
|
||||
stream, err = mg.mongoClient.Watch(CollectionFile, mongo.Pipeline{matchStage, projectStage}, options.ChangeStream().SetFullDocument(options.UpdateLookup))
|
||||
if err != nil {
|
||||
logger.Error("watchWhitelistCollection watch failed :", err)
|
||||
time.Sleep(time.Minute)
|
||||
logger.Error("watchFileCollection watch failed :", err)
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
ctx = context.TODO()
|
||||
@ -86,40 +88,42 @@ func (mg *Maingate) watchWhitelistCollection(parentctx context.Context) {
|
||||
|
||||
changed := stream.TryNext(ctx)
|
||||
if ctx.Err() != nil {
|
||||
logger.Error("watchServiceCollection stream.TryNext failed. process should be restarted! :", ctx.Err().Error())
|
||||
logger.Error("watchFileCollection stream.TryNext failed. process should be restarted! :", ctx.Err().Error())
|
||||
break
|
||||
}
|
||||
|
||||
if changed {
|
||||
var data whilelistPipelineDocument
|
||||
if err := stream.Decode(&data); err == nil {
|
||||
ot := data.OperationType
|
||||
switch ot {
|
||||
case "insert":
|
||||
// 새 화이트리스트 멤버
|
||||
if svc := mg.services.get(data.Member.Service); svc != nil {
|
||||
svc.wl.add(data.Member)
|
||||
}
|
||||
case "update":
|
||||
if svc := mg.services.get(data.Member.Service); svc != nil {
|
||||
if data.Member.Expired != 0 {
|
||||
logger.Println("whitelist member is removed :", *data.Member)
|
||||
svc.wl.remove(data.Member.Email)
|
||||
} else {
|
||||
logger.Println("whitelist member is updated :", *data.Member)
|
||||
svc.wl.add(data.Member)
|
||||
}
|
||||
}
|
||||
if !changed {
|
||||
if stream.Err() != nil || stream.ID() == 0 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
logger.Println("watchServiceCollection is done")
|
||||
stream.Close(ctx)
|
||||
return
|
||||
|
||||
case <-time.After(time.Second):
|
||||
logger.Error("watchServiceCollection stream error :", stream.Err())
|
||||
stream.Close(ctx)
|
||||
stream = nil
|
||||
}
|
||||
} else {
|
||||
logger.Error("watchServiceCollection stream.Decode failed :", err)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
var data filePipelineDocument
|
||||
if err := stream.Decode(&data); err == nil {
|
||||
switch data.OperationType {
|
||||
case "insert":
|
||||
data.File.Save()
|
||||
|
||||
case "delete":
|
||||
subfolder := hex.EncodeToString(data.DocumentKey.Id[:4])
|
||||
rf := hex.EncodeToString(data.DocumentKey.Id[4:8])
|
||||
|
||||
subpath := path.Join("static", subfolder, rf)
|
||||
os.RemoveAll(subpath)
|
||||
}
|
||||
} else if stream.Err() != nil || stream.ID() == 0 {
|
||||
logger.Error("watchServiceCollection stream error :", stream.Err())
|
||||
stream.Close(ctx)
|
||||
stream = nil
|
||||
} else {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,7 +141,6 @@ func (mg *Maingate) watchServiceCollection(parentctx context.Context, serveMux *
|
||||
Key: "$match", Value: bson.D{
|
||||
{Key: "operationType", Value: bson.D{
|
||||
{Key: "$in", Value: bson.A{
|
||||
"delete",
|
||||
"insert",
|
||||
"update",
|
||||
"replace",
|
||||
@ -185,9 +188,11 @@ func (mg *Maingate) watchServiceCollection(parentctx context.Context, serveMux *
|
||||
if err := data.Service.prepare(mg); err != nil {
|
||||
logger.Error("service cannot be prepared :", data.Service, err)
|
||||
} else {
|
||||
logger.Println("service is on the board! :", data.Service)
|
||||
mg.services.add(data.Service)
|
||||
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, data.Service.ServiceCode, "/"), data.Service)
|
||||
// 내가 임시로 가지고 있던 서비스일 수 있다.
|
||||
if mg.service().Id == data.Service.Id {
|
||||
logger.Println("service is on the board! :", data.Service)
|
||||
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(data.Service))
|
||||
}
|
||||
}
|
||||
|
||||
case "replace":
|
||||
@ -195,65 +200,30 @@ func (mg *Maingate) watchServiceCollection(parentctx context.Context, serveMux *
|
||||
|
||||
case "update":
|
||||
data.Service.prepare(mg)
|
||||
if old := mg.services.get(data.Service.ServiceName); old != nil {
|
||||
logger.Printf("service is changed : %v", data.Service)
|
||||
|
||||
atomic.SwapPointer(&old.divisionsSerialized, data.Service.divisionsSerialized)
|
||||
atomic.SwapPointer(&old.apiUsers, data.Service.apiUsers)
|
||||
atomic.SwapPointer(&old.serviceSerialized, data.Service.serviceSerialized)
|
||||
|
||||
for _, token := range old.ServerApiTokens {
|
||||
mg.apiTokenToService.remove(token.Hex())
|
||||
}
|
||||
|
||||
for _, token := range data.Service.ServerApiTokens {
|
||||
mg.apiTokenToService.add(token.Hex(), data.Service.ServiceCode)
|
||||
}
|
||||
|
||||
if data.Service.UseWhitelist {
|
||||
atomic.StoreInt32(&old.wl.working, 1)
|
||||
} else {
|
||||
atomic.StoreInt32(&old.wl.working, 0)
|
||||
}
|
||||
|
||||
old.Closed = data.Service.Closed
|
||||
if old.Closed {
|
||||
atomic.StoreInt32(&old.closed, 1)
|
||||
} else {
|
||||
atomic.StoreInt32(&old.closed, 0)
|
||||
}
|
||||
atomic.SwapPointer(&old.wl.emailptr, data.Service.wl.emailptr)
|
||||
|
||||
old.Divisions = data.Service.Divisions
|
||||
} else if !data.Service.Closed {
|
||||
if err := data.Service.prepare(mg); err != nil {
|
||||
logger.Error("service cannot be prepared :", data.Service, err)
|
||||
} else {
|
||||
logger.Println("service is on the board! :", data.Service)
|
||||
mg.services.add(data.Service)
|
||||
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, data.Service.ServiceCode, "/"), data.Service)
|
||||
}
|
||||
}
|
||||
case "delete":
|
||||
if deleted := mg.services.remove(data.DocumentKey.Id); deleted != nil {
|
||||
logger.Println("service is closed :", data.Service)
|
||||
atomic.AddInt32(&deleted.closed, 1)
|
||||
}
|
||||
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(data.Service))
|
||||
}
|
||||
} else {
|
||||
logger.Error("watchServiceCollection stream.Decode failed :", err)
|
||||
}
|
||||
} else if stream.Err() != nil || stream.ID() == 0 {
|
||||
logger.Error("watchServiceCollection stream error :", stream.Err())
|
||||
stream.Close(ctx)
|
||||
stream = nil
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
logger.Println("watchServiceCollection is done")
|
||||
stream.Close(ctx)
|
||||
return
|
||||
|
||||
case <-time.After(time.Second):
|
||||
logger.Error("watchServiceCollection stream error :", stream.Err())
|
||||
stream.Close(ctx)
|
||||
stream = nil
|
||||
}
|
||||
} else {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func watchAuthCollection(parentctx context.Context, ac *common.AuthCollection, mongoClient common.MongoClient) {
|
||||
func watchAuthCollection(parentctx context.Context, ac *gocommon.AuthCollection, mongoClient gocommon.MongoClient) {
|
||||
defer func() {
|
||||
s := recover()
|
||||
if s != nil {
|
||||
@ -320,9 +290,17 @@ func watchAuthCollection(parentctx context.Context, ac *common.AuthCollection, m
|
||||
logger.Error("watchAuthCollection stream.Decode failed :", err)
|
||||
}
|
||||
} else if stream.Err() != nil || stream.ID() == 0 {
|
||||
logger.Error("watchAuthCollection stream error :", stream.Err())
|
||||
stream.Close(ctx)
|
||||
stream = nil
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
logger.Println("watchAuthCollection is done")
|
||||
stream.Close(ctx)
|
||||
return
|
||||
|
||||
case <-time.After(time.Second):
|
||||
logger.Error("watchAuthCollection stream error :", stream.Err())
|
||||
stream.Close(ctx)
|
||||
stream = nil
|
||||
}
|
||||
} else {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
11
fba/track-event.html
Normal file
11
fba/track-event.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<script type="text/javascript" src="./fb-ga.min.js">
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!-- <body> -->
|
||||
<!-- <body onload="window.FBA.TrackLogEvent('DESKTOP-TEST');"> -->
|
||||
<!-- <script type="cjs" src="./fb-ga.rollup.js"> -->
|
||||
60
go.mod
60
go.mod
@ -1,55 +1,57 @@
|
||||
module repositories.action2quare.com/ayo/maingate
|
||||
|
||||
go 1.19
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
firebase.google.com/go v3.13.0+incompatible
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
go.mongodb.org/mongo-driver v1.11.6
|
||||
google.golang.org/api v0.124.0
|
||||
repositories.action2quare.com/ayo/go-ayo v0.0.0-20230524030148-5cf64e74bbfa
|
||||
go.mongodb.org/mongo-driver v1.11.7
|
||||
google.golang.org/api v0.128.0
|
||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20230912075917-f9a146321cdb
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.110.0 // indirect
|
||||
cloud.google.com/go/compute v1.19.0 // indirect
|
||||
cloud.google.com/go v0.110.2 // indirect
|
||||
cloud.google.com/go/compute v1.20.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/firestore v1.9.0 // indirect
|
||||
cloud.google.com/go/iam v0.13.0 // indirect
|
||||
cloud.google.com/go/longrunning v0.4.1 // indirect
|
||||
cloud.google.com/go/storage v1.28.1 // indirect
|
||||
cloud.google.com/go/firestore v1.10.0 // indirect
|
||||
cloud.google.com/go/iam v1.1.1 // indirect
|
||||
cloud.google.com/go/longrunning v0.5.1 // indirect
|
||||
cloud.google.com/go/storage v1.30.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/s2a-go v0.1.4 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.8.0 // indirect
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.11.0 // indirect
|
||||
github.com/klauspost/compress v1.16.6 // indirect
|
||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||
github.com/pires/go-proxyproto v0.7.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.1 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.3 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // 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-20201027041543-1326539a0a0a // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
golang.org/x/crypto v0.9.0 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/oauth2 v0.8.0 // indirect
|
||||
golang.org/x/sync v0.2.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
golang.org/x/time v0.1.0 // indirect
|
||||
golang.org/x/crypto v0.10.0 // indirect
|
||||
golang.org/x/net v0.11.0 // indirect
|
||||
golang.org/x/oauth2 v0.9.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.9.0 // indirect
|
||||
golang.org/x/text v0.10.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
google.golang.org/grpc v1.55.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
||||
google.golang.org/grpc v1.56.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
)
|
||||
|
||||
replace repositories.action2quare.com/ayo/maingate => ./
|
||||
replace repositories.action2quare.com/ayo/maingate => ./
|
||||
|
||||
106
go.sum
106
go.sum
@ -1,19 +1,19 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys=
|
||||
cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY=
|
||||
cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ=
|
||||
cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU=
|
||||
cloud.google.com/go v0.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA=
|
||||
cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw=
|
||||
cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg=
|
||||
cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/firestore v1.9.0 h1:IBlRyxgGySXu5VuW0RgGFlTtLukSnNkpDiEOMkQkmpA=
|
||||
cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE=
|
||||
cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k=
|
||||
cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=
|
||||
cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM=
|
||||
cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo=
|
||||
cloud.google.com/go/storage v1.28.1 h1:F5QDG5ChchaAVQhINh24U99OWHURqrW8OmQcGKXcbgI=
|
||||
cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y=
|
||||
cloud.google.com/go/firestore v1.10.0 h1:FG5C49ukKKqyljY+XNRZGae1HZaiVe7aoqi2BipnBuM=
|
||||
cloud.google.com/go/firestore v1.10.0/go.mod h1:eAeoQCV8F35Mcy4k8ZrQbcSYZOayIwoiU7ZJ6xzH1+o=
|
||||
cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y=
|
||||
cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU=
|
||||
cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI=
|
||||
cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc=
|
||||
cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
|
||||
cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
|
||||
firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4=
|
||||
firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
@ -47,8 +47,9 @@ github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq
|
||||
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/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@ -66,8 +67,9 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/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/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
@ -84,20 +86,22 @@ github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkj
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
||||
github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc=
|
||||
github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w=
|
||||
github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4=
|
||||
github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk=
|
||||
github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
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/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
@ -123,25 +127,29 @@ github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
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.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
|
||||
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.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
|
||||
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/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver v1.11.6 h1:XM7G6PjiGAO5betLF13BIa5TlLUUE3uJ/2Ox3Lz1K+o=
|
||||
go.mongodb.org/mongo-driver v1.11.6/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY=
|
||||
go.mongodb.org/mongo-driver v1.11.7 h1:LIwYxASDLGUg/8wOhgOOZhX8tQa/9tgZPgzZoVqJvcs=
|
||||
go.mongodb.org/mongo-driver v1.11.7/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
@ -160,20 +168,20 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
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.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
|
||||
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
||||
golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs=
|
||||
golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -184,8 +192,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
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.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.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=
|
||||
@ -194,10 +202,10 @@ 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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
|
||||
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
@ -210,8 +218,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
google.golang.org/api v0.124.0 h1:dP6Ef1VgOGqQ8eiv4GiY8RhmeyqzovcXBYPDUYG8Syo=
|
||||
google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4=
|
||||
google.golang.org/api v0.128.0 h1:RjPESny5CnQRn9V6siglged+DZCgfu9l6mO9dkX9VOg=
|
||||
google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
@ -220,8 +228,12 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
||||
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao=
|
||||
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
@ -230,8 +242,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||
google.golang.org/grpc v1.56.0 h1:+y7Bs8rtMd07LeXmL3NxcTLn7mUkbKZqEpPhMNkwJEE=
|
||||
google.golang.org/grpc v1.56.0/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@ -256,5 +268,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
repositories.action2quare.com/ayo/go-ayo v0.0.0-20230524030148-5cf64e74bbfa h1:mlRZAjs1adM8UVad00SQ2tWvhCzZqbKcHmAyjc4NnjY=
|
||||
repositories.action2quare.com/ayo/go-ayo v0.0.0-20230524030148-5cf64e74bbfa/go.mod h1:AKV0q5x39cg3+l7be0B2QaQhHGcBf+eLdlcWd1lgs70=
|
||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20230912075917-f9a146321cdb h1:Rdf6uhBIWunRLZ2LIT1hSovYXxZoOzx9mdSK5bjWpos=
|
||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20230912075917-f9a146321cdb/go.mod h1:rn6NA28Mej+qgLNx/Bu2wsdGyIycmacqlNP6gUXX2a0=
|
||||
|
||||
16
main.go
16
main.go
@ -2,25 +2,23 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"repositories.action2quare.com/ayo/gocommon"
|
||||
"repositories.action2quare.com/ayo/gocommon/flagx"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
"repositories.action2quare.com/ayo/maingate/core"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/common"
|
||||
"repositories.action2quare.com/ayo/go-ayo/logger"
|
||||
)
|
||||
|
||||
// linux : go build --ldflags="-X 'main.revision=$(git rev-parse --short HEAD)'"
|
||||
// windows : for /f usebackq %F in (`git rev-parse --short HEAD`) do go build --ldflags="-X 'main.revision=%F'"
|
||||
var revision = "0000000"
|
||||
var prefix = flagx.String("prefix", "", "")
|
||||
|
||||
func main() {
|
||||
if !flag.Parsed() {
|
||||
flag.Parse()
|
||||
}
|
||||
flagx.Parse()
|
||||
|
||||
logger.Println("build revision =", revision)
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
@ -33,12 +31,12 @@ func main() {
|
||||
}
|
||||
|
||||
serveMux := http.NewServeMux()
|
||||
if err := mg.RegisterHandlers(ctx, serveMux, *common.PrefixPtr); err != nil {
|
||||
if err := mg.RegisterHandlers(ctx, serveMux, *prefix); err != nil {
|
||||
logger.Error("RegisterHandlers failed :", err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
server := common.NewHTTPServer(serveMux)
|
||||
server := gocommon.NewHTTPServer(serveMux)
|
||||
logger.Println("maingate is started")
|
||||
if err := server.Start(); err != nil {
|
||||
logger.Error("maingate is stopped with error :", err)
|
||||
|
||||
14
make_maingate_package.ps1
Normal file
14
make_maingate_package.ps1
Normal file
@ -0,0 +1,14 @@
|
||||
# $ErrorActionPreference = 'SilentlyContinue'
|
||||
|
||||
$CurBranch = git branch --show-current
|
||||
|
||||
Remove-Item maingate.zip -Force -Recurse -ErrorAction SilentlyContinue
|
||||
|
||||
$Env:GOOS="linux"
|
||||
$Env:GOARCH="amd64"
|
||||
go build -ldflags="-s -w" .
|
||||
|
||||
Compress-Archive -Path maingate -Update -DestinationPath maingate.zip
|
||||
Compress-Archive -Path *-firebase-*.json -Update -DestinationPath maingate.zip
|
||||
Compress-Archive -Path fba -Update -DestinationPath maingate.zip
|
||||
Compress-Archive -Path template -Update -DestinationPath maingate.zip
|
||||
1
template/fb-ga.min.js
vendored
Normal file
1
template/fb-ga.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
223
www/gamepot.html
223
www/gamepot.html
@ -1,223 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>GamePot JS SDK Sandbox</title>
|
||||
<meta charset="utf-8" />
|
||||
<!-- <meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||
/> -->
|
||||
|
||||
<!-- <link
|
||||
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
|
||||
rel="stylesheet"
|
||||
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
|
||||
crossorigin="anonymous"
|
||||
/> -->
|
||||
<!-- <script src="https://gamepot.gcdn.ntruss.com/gamepot-sdk-javascript-lastest.min.js"></script> -->
|
||||
<script src="https://cdn.gamepot.io/dev/gamepot-sdk-javascript-1.0.19-b1.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="container-fluid" style="margin-bottom: 200px;">
|
||||
<script type="text/javascript">
|
||||
|
||||
function onLoginsuccess(user) {
|
||||
// -- 로그인 성공
|
||||
// id: 회원 아이디
|
||||
// token: 로그인 토큰(JWT)
|
||||
// nickname: 닉네임
|
||||
// provider: 소셜 로그인 종류
|
||||
// providerId: 소셜 로그인 ID
|
||||
// verify: 인증여부
|
||||
// agree: 약관 동의 여부
|
||||
//===========================
|
||||
|
||||
const formauth = document.createElement('form');
|
||||
let objs1 = document.createElement('input');
|
||||
objs1.setAttribute('type', 'hidden');
|
||||
objs1.setAttribute('name', 'state');
|
||||
objs1.setAttribute('value', '{{ .State }}');
|
||||
formauth.appendChild(objs1);
|
||||
|
||||
let objs2 = document.createElement('input');
|
||||
objs2.setAttribute('type', 'hidden');
|
||||
objs2.setAttribute('name', 'id');
|
||||
objs2.setAttribute('value', `${user.id}`);
|
||||
formauth.appendChild(objs2);
|
||||
|
||||
let objs3 = document.createElement('input');
|
||||
objs3.setAttribute('type', 'hidden');
|
||||
objs3.setAttribute('name', 'code');
|
||||
objs3.setAttribute('value', `${user.token}`);
|
||||
formauth.appendChild(objs3);
|
||||
|
||||
let objs4 = document.createElement('input');
|
||||
objs4.setAttribute('type', 'hidden');
|
||||
objs4.setAttribute('name', 'nickname');
|
||||
objs4.setAttribute('value', `${user.nickname}`);
|
||||
formauth.appendChild(objs4);
|
||||
|
||||
let objs5 = document.createElement('input');
|
||||
objs5.setAttribute('type', 'hidden');
|
||||
objs5.setAttribute('name', 'provider');
|
||||
objs5.setAttribute('value', `${user.provider}`);
|
||||
formauth.appendChild(objs5);
|
||||
|
||||
let objs6 = document.createElement('input');
|
||||
objs6.setAttribute('type', 'hidden');
|
||||
objs6.setAttribute('name', 'providerId');
|
||||
objs6.setAttribute('value', `${user.providerId}`);
|
||||
formauth.appendChild(objs6);
|
||||
|
||||
let objs7 = document.createElement('input');
|
||||
objs7.setAttribute('type', 'hidden');
|
||||
objs7.setAttribute('name', 'verify');
|
||||
objs7.setAttribute('value', `${user.verify}`);
|
||||
formauth.appendChild(objs7);
|
||||
|
||||
let objs8 = document.createElement('input');
|
||||
objs8.setAttribute('type', 'hidden');
|
||||
objs8.setAttribute('name', 'agree');
|
||||
objs8.setAttribute('value', `${user.agree}`);
|
||||
formauth.appendChild(objs8);
|
||||
|
||||
formauth.setAttribute('method', 'post');
|
||||
formauth.setAttribute('action', '/authorize/gamepot');
|
||||
document.body.appendChild(formauth);
|
||||
formauth.submit();
|
||||
}
|
||||
|
||||
function onLoginFail(error) {
|
||||
const formauth = document.createElement('form');
|
||||
formauth.setAttribute('method', 'post');
|
||||
formauth.setAttribute('action', 'actionsquare://error?errormsg='+ encodeURIComponent(`${error.code}-${error.message}`));
|
||||
document.body.appendChild(formauth);
|
||||
formauth.submit();
|
||||
}
|
||||
|
||||
function onSignInGoogle(error, user) {
|
||||
if (error) {
|
||||
// 로그인 실패
|
||||
onLoginFail(error);
|
||||
} else {
|
||||
onLoginsuccess(user);
|
||||
}
|
||||
}
|
||||
|
||||
function SignIn(channeltype) {
|
||||
GP.login(channeltype, function (user, error) {
|
||||
if (error) {
|
||||
// 로그아웃 실패
|
||||
onLoginFail(error);
|
||||
} else {
|
||||
// 로그인 성공
|
||||
onLoginsuccess(user)
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function Logout() {
|
||||
// GP.logout(function (error) {});
|
||||
GP.logout(function (result, error) {
|
||||
if (error) {
|
||||
// 로그아웃 실패
|
||||
alert(error); // 오류 메세지
|
||||
} else {
|
||||
// 로그아웃 아웃 완료
|
||||
alert("로그아웃 아웃 완료");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteMember() {
|
||||
if (!userId) {
|
||||
alert("로그인을 먼저 해 주세요.");
|
||||
return;
|
||||
}
|
||||
GP.deleteMember(userId, function (result, error) {
|
||||
if (error) {
|
||||
// 회원탈퇴 실패
|
||||
alert(error); // 오류 메세지
|
||||
} else {
|
||||
// 회원탈퇴 아웃 완료
|
||||
alert("회원탈퇴 성공!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
// 프로젝트 ID는 게임팟 대시보드에서 확인할 수 있습니다.
|
||||
var project_id = "dbfe1334-6dde-43e0-b8a9-cc0733d4c60e";
|
||||
|
||||
var gamepotConfig = {
|
||||
|
||||
api_url: "https://gpapps.gamepot.ntruss.com",
|
||||
google_signin_client_id:
|
||||
"46698421246-aeg0c2pmsgifr3fi06jgnqag5u8ph3kn.apps.googleusercontent.com",
|
||||
google: {
|
||||
callback: onSignInGoogle, // callback 버튼
|
||||
renderButton: "googleRenderButton", // 버튼 DIV 이름
|
||||
option: {
|
||||
// google button option
|
||||
size: "large",
|
||||
theme: "outline",
|
||||
width: "375",
|
||||
text: "signup_with",
|
||||
shape: "rectangular",
|
||||
logo_alignment: "left",
|
||||
locale: "ko_kr"
|
||||
}
|
||||
},
|
||||
facebook_app_id: "2930531180541185",
|
||||
apple_client_id: "auth.service.action2quare.com",
|
||||
apple_redirect_uri: "{{.RedirectBaseUrl}}/authorize/apple",
|
||||
api_key: "b94615af2a956facd2add44ea50529154b35f520de85673d",
|
||||
};
|
||||
|
||||
GP.initialize(project_id, gamepotConfig);
|
||||
};
|
||||
|
||||
</script>
|
||||
<div align="center">
|
||||
|
||||
|
||||
<br />
|
||||
<div id="googleRenderButton"></div>
|
||||
<br />
|
||||
|
||||
|
||||
<div>
|
||||
<table class="table" border="0" width="400" bgcolor="white" style="table-layout: fixed" onclick="SignIn(GP.ChannelType.APPLE)">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<div
|
||||
id="appleid-signin"
|
||||
data-mode="center-align"
|
||||
data-type="sign-in"
|
||||
data-color="white"
|
||||
data-border="true"
|
||||
data-border-radius="15"
|
||||
data-width="375"
|
||||
data-height="40"
|
||||
data-logo-size="medium"
|
||||
data-logo-position="47"
|
||||
data-label-position="135"
|
||||
style="pointer-events: none"
|
||||
></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.4 KiB |
276
www/toCDN/gamepot-sdk-javascript-1.0.19-b1.min.js
vendored
276
www/toCDN/gamepot-sdk-javascript-1.0.19-b1.min.js
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user