Compare commits

..

29 Commits

Author SHA1 Message Date
e37a974d9c [이민권] 계정 삭제
- 계정 삭제 시, Firebase 정보 삭제
2024-01-12 12:31:21 +09:00
470591cb44 [이민권] 계정 삭제
- 계정 삭제 취소 기능 추가
2024-01-11 19:11:43 +09:00
38114769b3 [이민권] 계정 삭제
- 계정 삭제 취소 기능 추가
2024-01-11 12:54:48 +09:00
b05473a1c6 [이민권] 계정 삭제
- 계정 삭제 취소 기능 추가
2024-01-10 18:40:38 +09:00
0fff694e8a [이민권] 계정 삭제
- 계정 삭제 취소 기능 추가
2024-01-10 18:10:18 +09:00
d8713298c4 [이민권] 계정 삭제
- 계정 삭제 취소 기능 추가
2024-01-10 17:35:00 +09:00
763b0fc4bd [이민권] 계정 삭제
- 계정 삭제 취소 기능 추가
2024-01-10 17:28:24 +09:00
d8e18d7ffc [이민권] 서비스 준비
- 계정 삭제 시, TTL 적용
2024-01-09 19:56:57 +09:00
381f1edb80 [이민우] 정보가 아니라 주소갑이 나와서 수정 (대리 커밋) 2023-12-08 17:08:14 +09:00
a8e448b8ca 로그 정리 2023-10-30 17:25:39 +09:00
9b0e3a5d5b 모듈 정리 2023-10-30 17:25:31 +09:00
5757a81cb8 fba, template 폴더를 package 에 추가 2023-10-24 14:05:42 +09:00
c4b8e630dc [이민권] 에러 수정 2023-10-23 15:17:07 +09:00
43b0242652 Firebase-Google Analaytics Desktop 버전 연동을 위해서 JavaScript SDK( JS-SDk ) 관련 코드 추가 2023-10-23 15:08:48 +09:00
893744a1ab Revert "모듈 업데이트"
This reverts commit 192cc569b4.
2023-10-12 12:04:49 +09:00
192cc569b4 모듈 업데이트 2023-10-12 12:04:31 +09:00
56e6608537 화이트리스트 추가,삭제 반영 안되는 문제 수정 2023-10-05 11:08:09 +09:00
0053033e32 현재 block된 정보를 조회 2023-09-25 12:29:41 +09:00
d1ff6a56fc gocommon 업데이트 반영 2023-09-21 13:18:41 +09:00
114461c51d 화이트리스트 추가 안되는 문제 수정 2023-09-12 17:07:16 +09:00
117a3e5d90 [이민우] 캐릭터 생성 제한 구현 (대신 커밋) 2023-09-08 18:24:17 +09:00
fafc463f2a [이민우] 캐릭터 생성 제한 구현 (대신 커밋) 2023-09-06 19:34:47 +09:00
e2bec481f0 [이민우] 캐릭터 생성 제한 구현 (대신 커밋) 2023-09-06 17:11:47 +09:00
89e7d35b5a [이민권] 오타 수정 2023-09-06 11:35:21 +09:00
fe662c5355 [이민우] 캐릭터 생성 제한 구현 (대신 커밋) 2023-09-06 11:23:06 +09:00
6767a37704 version split 수정 2023-09-05 17:14:56 +09:00
2ea035a43b version split 수정 2023-09-04 11:15:23 +09:00
2a1ad499ed [이민우] 캐릭터 생성 제한 구현 (대신 커밋) 2023-08-31 17:19:18 +09:00
5cc6ddc8f1 [이민우] 캐릭터 생성 제한 구현 (대신 커밋) 2023-08-31 11:55:31 +09:00
20 changed files with 8791 additions and 103 deletions

View 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

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 it is too large Load Diff

537
backup/firebase-jssdk/js.js Normal file

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 it is too large Load Diff

View File

@ -1,6 +1,7 @@
{ {
"maingate_mongodb_url": "mongodb://...", "maingate_mongodb_url": "mongodb://...",
"autologin_ttl": 604800, "autologin_ttl": 604800,
"acc_del_ttl": 7776000,
"maximum_num_link_account": 10, "maximum_num_link_account": 10,
"redirect_base_url": "", "redirect_base_url": "",
"google_client_id" : "", "google_client_id" : "",
@ -25,6 +26,15 @@
"firebase_admin_sdk_credentialfile": "", "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" : [ "maingate_global_admins" : [
"mountain@action2quare.com" "mountain@action2quare.com"
] ]

View File

@ -161,8 +161,14 @@ func (caller apiCaller) uploadAPI(w http.ResponseWriter, r *http.Request) error
func (caller apiCaller) blockAPI(w http.ResponseWriter, r *http.Request) error { func (caller apiCaller) blockAPI(w http.ResponseWriter, r *http.Request) error {
mg := caller.mg mg := caller.mg
if r.Method == "GET" { if r.Method == "GET" {
enc := json.NewEncoder(w) target, ok := gocommon.ReadObjectIDFormValue(r.Form, "accid")
enc.Encode(mg.bl.all()) 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" { } else if r.Method == "PUT" {
body, _ := io.ReadAll(r.Body) body, _ := io.ReadAll(r.Body)
@ -233,7 +239,7 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
return err return err
} }
member.ExpiredAt = 0 member.ExpiredAt = 0
member.Id = primitive.NilObjectID
_, _, err := mg.mongoClient.Update(CollectionWhitelist, bson.M{ _, _, err := mg.mongoClient.Update(CollectionWhitelist, bson.M{
"_id": primitive.NewObjectID(), "_id": primitive.NewObjectID(),
}, bson.M{ }, bson.M{
@ -397,6 +403,40 @@ func (caller apiCaller) configAPI(w http.ResponseWriter, r *http.Request) error
return nil return nil
} }
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 { type apiCaller struct {
userinfo map[string]any userinfo map[string]any
globalAdmins map[string]bool globalAdmins map[string]bool
@ -503,6 +543,8 @@ func (mg *Maingate) api(w http.ResponseWriter, r *http.Request) {
err = caller.blockAPI(w, r) err = caller.blockAPI(w, r)
} else if strings.HasSuffix(r.URL.Path, "/coupon") { } else if strings.HasSuffix(r.URL.Path, "/coupon") {
err = caller.couponAPI(w, r) err = caller.couponAPI(w, r)
} else if strings.HasSuffix(r.URL.Path, "/lockcreatechar") {
err = caller.lockcreatecharAPI(w, r)
} }
if err != nil { if err != nil {

View File

@ -21,7 +21,7 @@ func TestMakeLocalUniqueId(t *testing.T) {
fmt.Println(start.Time().Format(time.RFC3339)) fmt.Println(start.Time().Format(time.RFC3339))
fmt.Println(end.Time().Format(time.RFC3339)) fmt.Println(end.Time().Format(time.RFC3339))
mongoClient, err := gocommon.NewMongoClient(context.Background(), "mongodb://121.134.91.160:27018/?replicaSet=rs0&retrywrites=true", "mountain-maingate") mongoClient, err := gocommon.NewMongoClient(context.Background(), "mongodb://121.134.91.160:27018/mountain-maingate?replicaSet=rs0&retrywrites=true", "maingate")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

View File

@ -16,6 +16,7 @@ import (
"runtime/debug" "runtime/debug"
"strings" "strings"
"sync/atomic" "sync/atomic"
"text/template"
"time" "time"
"unsafe" "unsafe"
@ -123,6 +124,7 @@ type maingateConfig struct {
Mongo string `json:"maingate_mongodb_url"` Mongo string `json:"maingate_mongodb_url"`
SessionTTL int64 `json:"maingate_session_ttl"` SessionTTL int64 `json:"maingate_session_ttl"`
Autologin_ttl int64 `json:"autologin_ttl"` Autologin_ttl int64 `json:"autologin_ttl"`
AccDelTTL int64 `json:"acc_del_ttl"`
MaximumNumLinkAccount int64 `json:"maximum_num_link_account"` MaximumNumLinkAccount int64 `json:"maximum_num_link_account"`
RedirectBaseUrl string `json:"redirect_base_url"` RedirectBaseUrl string `json:"redirect_base_url"`
GoogleClientId string `json:"google_client_id"` GoogleClientId string `json:"google_client_id"`
@ -143,6 +145,18 @@ type maingateConfig struct {
FirebaseAdminSDKCredentialFile string `json:"firebase_admin_sdk_credentialfile"` FirebaseAdminSDKCredentialFile string `json:"firebase_admin_sdk_credentialfile"`
SteamAppId string `json:"steam_app_id"` SteamAppId string `json:"steam_app_id"`
SteamPublisherAuthKey string `json:"steam_publisher_authkey"` 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 { type globalAdmins struct {
@ -341,6 +355,14 @@ func (mg *Maingate) prepare(context context.Context) (err error) {
return makeErrorWithStack(err) 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에 삭제 알려주기 위함 // Delete대신 _ts로 expire시킴. pipeline에 삭제 알려주기 위함
if err = mg.mongoClient.MakeExpireIndex(CollectionWhitelist, 10); err != nil { if err = mg.mongoClient.MakeExpireIndex(CollectionWhitelist, 10); err != nil {
return makeErrorWithStack(err) return makeErrorWithStack(err)
@ -350,11 +372,6 @@ func (mg *Maingate) prepare(context context.Context) (err error) {
return makeErrorWithStack(err) return makeErrorWithStack(err)
} }
if *devflag {
// 에러 체크하지 말것
mg.mongoClient.DropIndex(CollectionBlock, "codeaccid")
}
if err = mg.mongoClient.MakeExpireIndex(CollectionBlock, int32(3)); err != nil { if err = mg.mongoClient.MakeExpireIndex(CollectionBlock, int32(3)); err != nil {
return makeErrorWithStack(err) return makeErrorWithStack(err)
} }
@ -474,8 +491,9 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
empty.Divisions = map[string]*Division{ empty.Divisions = map[string]*Division{
host: { host: {
DivisionForUser: DivisionForUser{ DivisionForUser: DivisionForUser{
Priority: 0, Priority: 0,
State: DivisionState_FullOpen, State: DivisionState_FullOpen,
LockCreateChar: false,
}, },
Url: fmt.Sprintf("http://%s/warehouse", ipaddr), Url: fmt.Sprintf("http://%s/warehouse", ipaddr),
@ -552,6 +570,14 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
serveMux.Handle(pattern, http.StripPrefix(pattern, staticfs)) serveMux.Handle(pattern, http.StripPrefix(pattern, staticfs))
logger.Println("maingate static registered :", pattern) logger.Println("maingate static registered :", pattern)
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(gocommon.MakeHttpHandlerPattern(prefix, "fba", "fb-ga.min.js"), mg.google_analytics_js)
logger.Println("google_analytics.js static registered :", pattern)
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformGoogle), mg.platform_google_get_login_url) 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", AuthPlatformGoogle), mg.platform_google_authorize)
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformGoogle), mg.platform_google_authorize_result) serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformGoogle), mg.platform_google_authorize_result)
@ -958,3 +984,31 @@ func JWTparseCode(keyurl string, code string) (string, string, string) {
//--- nonce 체크 필요하다. //--- nonce 체크 필요하다.
return claims["sub"].(string), email, 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
}
}

View File

@ -42,6 +42,14 @@ func (p *memberContainerPtr[K, T]) add(m T) {
atomic.StorePointer(&p.ptr, unsafe.Pointer(&next)) 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) { func (p *memberContainerPtr[K, T]) remove(key K) {
ptr := atomic.LoadPointer(&p.ptr) ptr := atomic.LoadPointer(&p.ptr)
src := (*map[K]T)(ptr) src := (*map[K]T)(ptr)
@ -87,7 +95,7 @@ func (p *memberContainerPtr[K, T]) contains(key K, out *T) bool {
return false return false
} }
if out != nil { if out != nil {
out = &found *out = found
} }
return true return true
} }

View File

@ -34,7 +34,7 @@ type blockinfoWithStringId struct {
} }
type whitelistmember struct { type whitelistmember struct {
Id primitive.ObjectID `bson:"_id" json:"_id"` Id primitive.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"`
Email string `bson:"email" json:"email"` Email string `bson:"email" json:"email"`
Platform string `bson:"platform" json:"platform"` Platform string `bson:"platform" json:"platform"`
Desc string `bson:"desc" json:"desc"` Desc string `bson:"desc" json:"desc"`
@ -88,9 +88,10 @@ type Maintenance struct {
} }
type DivisionForUser struct { type DivisionForUser struct {
Priority int `bson:"priority" json:"priority"` Priority int `bson:"priority" json:"priority"`
State DivisionStateName `bson:"state" json:"state"` State DivisionStateName `bson:"state" json:"state"`
Maintenance *Maintenance `bson:"maintenance,omitempty" json:"maintenance,omitempty"` LockCreateChar bool `bson:"lockcreatechar" json:"lockcreatechar"`
Maintenance *Maintenance `bson:"maintenance,omitempty" json:"maintenance,omitempty"`
} }
type Division struct { type Division struct {
@ -111,8 +112,8 @@ type serviceDescription struct {
VersionSplits map[string]string `bson:"version_splits" json:"version_splits"` VersionSplits map[string]string `bson:"version_splits" json:"version_splits"`
auths *gocommon.AuthCollection auths *gocommon.AuthCollection
wl memberContainerPtr[string, *whitelistmember] wl *memberContainerPtr[string, *whitelistmember]
bl memberContainerPtr[primitive.ObjectID, *blockinfo] bl *memberContainerPtr[primitive.ObjectID, *blockinfo]
mongoClient gocommon.MongoClient mongoClient gocommon.MongoClient
sessionTTL time.Duration sessionTTL time.Duration
@ -122,11 +123,9 @@ type serviceDescription struct {
updateUserinfo func(info usertokeninfo) (bool, string, string) updateUserinfo func(info usertokeninfo) (bool, string, string)
getProviderInfo func(platform string, uid string) (string, string, error) getProviderInfo func(platform string, uid string) (string, string, error)
divisionsForUsersSerialized []byte divisionsSerialized []byte
divisionsSerialized []byte serviceSerialized []byte
serviceSerialized []byte divisionsSplits map[string][]byte
serviceSummarySerialized []byte
divisionsSplits map[string][]byte
} }
func (sh *serviceDescription) isValidToken(apiToken primitive.ObjectID) bool { func (sh *serviceDescription) isValidToken(apiToken primitive.ObjectID) bool {
@ -188,11 +187,10 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
} }
divsForUsers := make(map[string]*DivisionForUser) divsForUsers := make(map[string]*DivisionForUser)
var namesOnly []string defaultDivNames := make(map[string]bool)
for dn, div := range divs { for dn, div := range divs {
namesOnly = append(namesOnly, dn) if div.State != DivisionState_Closed {
if div.State == DivisionState_Closed { defaultDivNames[dn] = true
continue
} }
divsForUsers[dn] = &div.DivisionForUser divsForUsers[dn] = &div.DivisionForUser
@ -229,25 +227,30 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
} }
sh.divisionsSerialized, _ = json.Marshal(divs) sh.divisionsSerialized, _ = json.Marshal(divs)
sh.divisionsForUsersSerialized, _ = json.Marshal(divsForUsers)
if len(sh.VersionSplits) == 0 {
sh.VersionSplits = map[string]string{
"default": strings.Join(namesOnly, ","),
}
}
sh.divisionsSplits = make(map[string][]byte) sh.divisionsSplits = make(map[string][]byte)
for ver, divnamesT := range sh.VersionSplits { for ver, divnamesT := range sh.VersionSplits {
if ver == "default" {
continue
}
divnames := strings.Split(divnamesT, ",") divnames := strings.Split(divnamesT, ",")
split := make(map[string]*DivisionForUser) split := make(map[string]*DivisionForUser)
for _, divname := range divnames { for _, divname := range divnames {
split[divname] = divsForUsers[divname] split[divname] = divsForUsers[divname]
// 스플릿 된 버전은 default에서 제거해야 한다.
delete(defaultDivNames, divname)
} }
splitMarshaled, _ := json.Marshal(split) splitMarshaled, _ := json.Marshal(split)
sh.divisionsSplits[ver] = splitMarshaled sh.divisionsSplits[ver] = splitMarshaled
} }
defaultsDivs := make(map[string]*DivisionForUser)
for divname := range defaultDivNames {
defaultsDivs[divname] = divsForUsers[divname]
}
defaultMarshaled, _ := json.Marshal(defaultsDivs)
sh.divisionsSplits["default"] = defaultMarshaled
sh.MaximumNumLinkAccount = mg.maingateConfig.MaximumNumLinkAccount sh.MaximumNumLinkAccount = mg.maingateConfig.MaximumNumLinkAccount
sh.mongoClient = mg.mongoClient sh.mongoClient = mg.mongoClient
sh.auths = mg.auths sh.auths = mg.auths
@ -258,9 +261,8 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
sh.updateUserinfo = mg.updateUserinfo sh.updateUserinfo = mg.updateUserinfo
sh.getProviderInfo = mg.getProviderInfo sh.getProviderInfo = mg.getProviderInfo
sh.wl = mg.wl sh.wl = &mg.wl
sh.bl = mg.bl sh.bl = &mg.bl
sh.serviceSummarySerialized, _ = json.Marshal(sh.ServiceDescriptionSummary)
sh.serviceSerialized, _ = json.Marshal(sh) sh.serviceSerialized, _ = json.Marshal(sh)
logger.Println("service is ready :", sh.ServiceCode, string(sh.serviceSerialized)) logger.Println("service is ready :", sh.ServiceCode, string(sh.serviceSerialized))
@ -320,7 +322,7 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
if !guestlink { if !guestlink {
_, err = sh.readProfile(oldType, oldId, bfinfo) _, err = sh.readProfile(oldType, oldId, bfinfo)
if err != nil { if err != nil {
logger.Error("readProfile(old) failed :", err) logger.Println("readProfile(old) failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
@ -330,7 +332,7 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
oldType, oldId, err = sh.getProviderInfo(oldType, oldId) oldType, oldId, err = sh.getProviderInfo(oldType, oldId)
if err != nil { if err != nil {
logger.Error("getProviderInfo failed :", err) logger.Println("getProviderInfo failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
@ -344,7 +346,7 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
email, err := sh.readProfile(newType, newId, bfinfo) email, err := sh.readProfile(newType, newId, bfinfo)
if err != nil { if err != nil {
logger.Error("readProfile(new) failed :", err) logger.Println("readProfile(new) failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
@ -357,7 +359,7 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
newType, newId, err = sh.getProviderInfo(newType, newId) newType, newId, err = sh.getProviderInfo(newType, newId)
if err != nil { if err != nil {
logger.Error("getProviderInfo failed :", err) logger.Println("getProviderInfo failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
@ -388,7 +390,7 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
}, options.Update().SetUpsert(true)) }, options.Update().SetUpsert(true))
if err != nil { if err != nil {
logger.Error("link failed. Update ServiceName err :", err) logger.Error("link failed. Update ServiceName err :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusInternalServerError)
return return
} }
@ -455,7 +457,7 @@ func (sh *serviceDescription) unlink(w http.ResponseWriter, r *http.Request) {
sType, sId, err := sh.getProviderInfo(sType, sId) sType, sId, err := sh.getProviderInfo(sType, sId)
if err != nil { if err != nil {
logger.Error("getProviderInfo failed :", err) logger.Println("getProviderInfo failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
@ -474,7 +476,7 @@ func (sh *serviceDescription) unlink(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
logger.Error("unlink failed, fail to count accounts :", err) logger.Error("unlink failed, fail to count accounts :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusInternalServerError)
} }
if len(accDocs) <= 1 { if len(accDocs) <= 1 {
@ -503,7 +505,7 @@ func (sh *serviceDescription) unlink(w http.ResponseWriter, r *http.Request) {
}, options.FindOneAndDelete().SetProjection(bson.M{"_id": 1})) }, options.FindOneAndDelete().SetProjection(bson.M{"_id": 1}))
if err != nil { if err != nil {
logger.Error("unlink failed. Delete ServiceName err :", err) logger.Error("unlink failed. Delete ServiceName err :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusInternalServerError)
return return
} }
if preid == nil { if preid == nil {
@ -552,7 +554,7 @@ func (sh *serviceDescription) linkinfo(w http.ResponseWriter, r *http.Request) {
sType, sId, err := sh.getProviderInfo(sType, sId) sType, sId, err := sh.getProviderInfo(sType, sId)
if err != nil { if err != nil {
logger.Error("getProviderInfo failed :", err) logger.Println("getProviderInfo failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
@ -572,7 +574,7 @@ func (sh *serviceDescription) linkinfo(w http.ResponseWriter, r *http.Request) {
})) }))
if err != nil { if err != nil {
logger.Error("linkinfo failed. CountDocuments err :", err) logger.Error("linkinfo failed. CountDocuments err :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusInternalServerError)
return return
} }
@ -586,6 +588,11 @@ func (sh *serviceDescription) linkinfo(w http.ResponseWriter, r *http.Request) {
}, options.Find().SetLimit(sh.MaximumNumLinkAccount).SetProjection(bson.M{ }, options.Find().SetLimit(sh.MaximumNumLinkAccount).SetProjection(bson.M{
platformName: 1, platformName: 1,
})) }))
if err != nil {
logger.Error("linkinfo failed. FindAll returns err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
var linkstrs []string var linkstrs []string
for _, link := range links { for _, link := range links {
@ -595,7 +602,7 @@ func (sh *serviceDescription) linkinfo(w http.ResponseWriter, r *http.Request) {
linkbytes, err := json.Marshal(linkstrs) linkbytes, err := json.Marshal(linkstrs)
if err != nil { if err != nil {
logger.Error("linkinfo failed. json marshal fail :", err) logger.Error("linkinfo failed. json marshal fail :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusInternalServerError)
return return
} }
@ -628,29 +635,29 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request)
//email, err := sh.readProfile(authtype, uid, accesstoken) //email, err := sh.readProfile(authtype, uid, accesstoken)
bfinfo, err := sh.getUserBrowserInfo(r) bfinfo, err := sh.getUserBrowserInfo(r)
if err != nil { if err != nil {
logger.Error("getUserBrowserInfo failed :", err) logger.Println("getUserBrowserInfo failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
email, err = sh.readProfile(authtype, uid, bfinfo) email, err = sh.readProfile(authtype, uid, bfinfo)
if err != nil { if err != nil {
logger.Error("readProfile failed :", err) logger.Println("readProfile failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
newType, newId, err := sh.getProviderInfo(authtype, uid) newType, newId, err := sh.getProviderInfo(authtype, uid)
if err != nil { if err != nil {
logger.Error("getProviderInfo failed :", err) logger.Println("getProviderInfo failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
if authtype != newType || uid != newId { if authtype != newType || uid != newId {
logger.Printf("auth success ( redirect ) : %s->%s, %s->%s, %s, %s", authtype, newType, uid, newId, email, session)
authtype = newType authtype = newType
uid = newId uid = newId
logger.Println("auth success ( redirect ) :", authtype, uid, email, session)
} }
} else { } else {
email = fmt.Sprintf("%s@guest.flag", uid) email = fmt.Sprintf("%s@guest.flag", uid)
@ -671,13 +678,15 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request)
"create": createtime, "create": createtime,
"email": email, "email": email,
}, },
}, options.FindOneAndUpdate().SetReturnDocument(options.After).SetUpsert(true).SetProjection(bson.M{"_id": 1})) }, options.FindOneAndUpdate().SetReturnDocument(options.After).SetUpsert(true).SetProjection(bson.M{
"_id": 1,
"_ts": 1,
}))
if err != nil { if err != nil {
logger.Error("authorize failed :", err) logger.Error("authorize failed :", err)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
linkid := link["_id"].(primitive.ObjectID) linkid := link["_id"].(primitive.ObjectID)
newaccid := primitive.NewObjectID() newaccid := primitive.NewObjectID()
for i := 0; i < len(sh.serviceCodeBytes); i++ { for i := 0; i < len(sh.serviceCodeBytes); i++ {
@ -731,6 +740,8 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request)
return return
} }
logger.Println("session created :", accid, authtype, uid, email, newsession)
output := map[string]any{ output := map[string]any{
"sk": newsession.Hex(), "sk": newsession.Hex(),
"expirein": sh.sessionTTL.Seconds(), "expirein": sh.sessionTTL.Seconds(),
@ -740,6 +751,14 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request)
if *noauth { if *noauth {
output["noauth"] = true output["noauth"] = true
} }
if link["_ts"] != nil {
delts := link["_ts"].(primitive.DateTime)
if !delts.Time().IsZero() {
// 삭제된 계정. 삭제 되었다고 알려주자
w.Header().Add("MG-ACCOUNT-DELETED", "TRUE")
}
}
bt, _ := json.Marshal(output) bt, _ := json.Marshal(output)
w.Write(bt) w.Write(bt)
} else if len(session) > 0 { } else if len(session) > 0 {
@ -755,8 +774,7 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request)
}, },
}, options.Update().SetUpsert(false)) }, options.Update().SetUpsert(false))
if err != nil { if err != nil {
logger.Error("update auth collection failed") logger.Error("update auth collection failed :", err)
logger.Error(err)
return return
} }
@ -771,6 +789,9 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request)
"sk": session, "sk": session,
"expirein": sh.sessionTTL.Seconds(), "expirein": sh.sessionTTL.Seconds(),
} }
logger.Println("session updated :", authtype, uid, session)
bt, _ := json.Marshal(output) bt, _ := json.Marshal(output)
w.Write(bt) w.Write(bt)
} else { } else {
@ -813,6 +834,7 @@ func (sh *serviceDescription) delacc(w http.ResponseWriter, r *http.Request) {
sType := queryvals.Get("stype") sType := queryvals.Get("stype")
sId := queryvals.Get("sid") sId := queryvals.Get("sid")
sk := queryvals.Get("sk") sk := queryvals.Get("sk")
cancel := queryvals.Has("cancel")
authInfo := sh.auths.Find(sk) authInfo := sh.auths.Find(sk)
if authInfo == nil { if authInfo == nil {
@ -828,7 +850,7 @@ func (sh *serviceDescription) delacc(w http.ResponseWriter, r *http.Request) {
return return
} }
accids, err := sh.mongoClient.FindAll(CollectionAccount, bson.M{ linkidMap, err := sh.mongoClient.FindAll(CollectionAccount, bson.M{
"accid": authInfo.Accid, "accid": authInfo.Accid,
}, options.Find().SetProjection(bson.M{ }, options.Find().SetProjection(bson.M{
"_id": 1, "_id": 1,
@ -839,27 +861,55 @@ func (sh *serviceDescription) delacc(w http.ResponseWriter, r *http.Request) {
return return
} }
var addIdFilter bson.A var linkidAry primitive.A
for _, accid := range accids { for _, linkid := range linkidMap {
addIdFilter = append(addIdFilter, accid["_id"].(primitive.ObjectID)) linkidAry = append(linkidAry, linkid["_id"].(primitive.ObjectID))
} }
delfilter := bson.D{{Key: "_id", Value: bson.D{{Key: "$in", Value: addIdFilter}}}} delfilter := primitive.M{"_id": bson.M{"$in": linkidAry}}
delaccnum, err := sh.mongoClient.DeleteMany(CollectionAccount, delfilter) var delop primitive.M
if err != nil { if !cancel {
logger.Error("delacc failed. Delete many CollectionAccount err :", err) curtime := primitive.NewDateTimeFromTime(time.Now().UTC())
w.WriteHeader(http.StatusBadRequest) delop = primitive.M{
"$set": primitive.M{"_ts": curtime},
}
if sType == AuthPlatformFirebaseAuth {
sh.mongoClient.Delete(CollectionFirebaseUserInfo, bson.M{
"firebaseuserid": sId,
})
}
} else {
delfilter["platform"] = sType
targetLinkId, err := sh.mongoClient.FindAll(CollectionLink, delfilter, options.Find().SetProjection(bson.M{
"_id": 1,
}))
if len(targetLinkId) != 1 {
logger.Error("delacc failed. FindAll link err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
delfilter = primitive.M{"_id": targetLinkId[0]["_id"].(primitive.ObjectID)}
delop = primitive.M{
"$unset": primitive.M{"_ts": true},
}
}
updated, _, err := sh.mongoClient.Update(CollectionAccount, delfilter, delop, options.Update().SetUpsert(false))
if !updated || err != nil {
logger.Error("delacc failed. Update CollectionAccount timestamp err :", err)
w.WriteHeader(http.StatusInternalServerError)
return return
} }
_, err = sh.mongoClient.DeleteMany(CollectionLink, delfilter) updated, _, err = sh.mongoClient.Update(CollectionLink, delfilter, delop, options.Update().SetUpsert(false))
if err != nil { if !updated || err != nil {
logger.Error("delacc failed. Delete many CollectionLink err :", err) logger.Error("delacc failed. Update CollectionLink timestamp err :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusInternalServerError)
return return
} }
logger.Println("delacc success :", delaccnum) logger.Println("delacc success :", linkidMap)
} }
func (sh *serviceDescription) serveHTTP(w http.ResponseWriter, r *http.Request) { func (sh *serviceDescription) serveHTTP(w http.ResponseWriter, r *http.Request) {
@ -962,7 +1012,7 @@ func (sh *serviceDescription) serveHTTP(w http.ResponseWriter, r *http.Request)
} }
} }
} else { } else {
logger.Println("div is not found :", divname) logger.Println("div is not found :", divname, sh.Divisions)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
} }
} else { } else {

537
fba/js.js Normal file

File diff suppressed because one or more lines are too long

11
fba/track-event.html Normal file
View 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"> -->

2
go.mod
View File

@ -7,7 +7,7 @@ require (
github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang-jwt/jwt v3.2.2+incompatible
go.mongodb.org/mongo-driver v1.11.7 go.mongodb.org/mongo-driver v1.11.7
google.golang.org/api v0.128.0 google.golang.org/api v0.128.0
repositories.action2quare.com/ayo/gocommon v0.0.0-20230825015501-e4527aa5b3ff repositories.action2quare.com/ayo/gocommon v0.0.0-20230912075917-f9a146321cdb
) )
require ( require (

32
go.sum
View File

@ -268,33 +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= 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-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/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/gocommon v0.0.0-20230612013915-5950ff4bb82e h1:m0jo1r+2NtBfxwj92e6EVaBZpzTDT6Hq7D93vWO4h9Y= repositories.action2quare.com/ayo/gocommon v0.0.0-20230912075917-f9a146321cdb h1:Rdf6uhBIWunRLZ2LIT1hSovYXxZoOzx9mdSK5bjWpos=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230612013915-5950ff4bb82e/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns= repositories.action2quare.com/ayo/gocommon v0.0.0-20230912075917-f9a146321cdb/go.mod h1:rn6NA28Mej+qgLNx/Bu2wsdGyIycmacqlNP6gUXX2a0=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230614091557-9b877d9a732c h1:fhCuu0jFps8T1sN8hO0fGnatvNDW6VwM96PV26EA3T4=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230614091557-9b877d9a732c/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230616031450-0b2c9351a717 h1:WrkkEWN3bh1QAulNJZjAiwXx2aPAj39OoIyJFUXmDaE=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230616031450-0b2c9351a717/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230616032216-378bc19f3742 h1:qEbzwVDz1w2ewNHu+vipzV+a804wmwRWe+0vnhCbJr4=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230616032216-378bc19f3742/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230620005911-15ba3e93d621 h1:9Hzdn13l9U0RJn9mMXsZQr+jsmsgy3zQFsBHPSOJnxM=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230620005911-15ba3e93d621/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230621051330-0d8752e66161 h1:sgixcFwdLOqcvwqTaKcsMEepXsLmNEgaybyur3QHRgk=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230621051330-0d8752e66161/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230621052811-06ef97f11d22 h1:DImSGNxZrc+Q4WlS1OKMsLAScEfDYLX4XMJdjAaVnXc=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230621052811-06ef97f11d22/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230710081612-3024a17b540f h1:MMA/6fqn76zSOkUQzG8v+IbWvrtY1mXN5xF1WOZonVc=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230710081612-3024a17b540f/go.mod h1:rn6NA28Mej+qgLNx/Bu2wsdGyIycmacqlNP6gUXX2a0=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230710084625-dd05ebf6ceb9 h1:dizJeTf3xt7wEeq72sYqlgdy7an8kezA6JuqALKPCBQ=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230710084625-dd05ebf6ceb9/go.mod h1:rn6NA28Mej+qgLNx/Bu2wsdGyIycmacqlNP6gUXX2a0=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230710085335-ead6543d95f9 h1:zJ+33DKEA6CObPii5c5l5IbUIws31+Ni5NzzC3oYRLw=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230710085335-ead6543d95f9/go.mod h1:rn6NA28Mej+qgLNx/Bu2wsdGyIycmacqlNP6gUXX2a0=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230710085810-8173216e9574 h1:Ha0d/sv/MzC3ASCTXfe2tAFJieLNJmTCBL8aETEOY14=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230710085810-8173216e9574/go.mod h1:rn6NA28Mej+qgLNx/Bu2wsdGyIycmacqlNP6gUXX2a0=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230801051747-b501160efc3b h1:yV1cBeu0GFxkDD6TDxzKv/rM3OMtyt1JXpeqDF5IO3Y=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230801051747-b501160efc3b/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230823084014-c34045e215fc h1:/nFKyjpcfMCdC7vrEZ7+IQOA5RoMmcBUHNRl40JN3ys=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230823084014-c34045e215fc/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230823134414-400c7f644333 h1:3QWHeK6eX1yhaeN/Lu88N4B2ORb/PdBkXUS+HzFOWgU=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230823134414-400c7f644333/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230825015501-e4527aa5b3ff h1:nTOqgPSfm0EANR1SFAi+Zi/KErAAlstVcEWWOnyDT5g=
repositories.action2quare.com/ayo/gocommon v0.0.0-20230825015501-e4527aa5b3ff/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw=

View File

@ -10,3 +10,5 @@ go build -ldflags="-s -w" .
Compress-Archive -Path maingate -Update -DestinationPath maingate.zip Compress-Archive -Path maingate -Update -DestinationPath maingate.zip
Compress-Archive -Path *-firebase-*.json -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

File diff suppressed because one or more lines are too long