diff --git a/.env b/.env index 9a82417..d87d58d 100644 --- a/.env +++ b/.env @@ -1,12 +1,41 @@ +# IP address to listen to SERVER=0.0.0.0 +# port to bind PORT=8080 +# Gin framework release mode GIN_MODE=release - +# where to write all generated config files WG_CONF_DIR=./wireguard +# WireGuard main config file name, generally .conf WG_INTERFACE_NAME=wg0.conf +# SMTP settings to send email to clients SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_USERNAME=account@gmail.com -SMTP_PASSWORD="*************" -SMTP_FROM="Wg Gen Web " +SMTP_PASSWORD=************* +SMTP_FROM=Wg Gen Web + +# example with gitlab, which is RFC implementation and no need any custom stuff +OAUTH2_PROVIDER_NAME=oauth2oidc +OAUTH2_PROVIDER=https://gitlab.com +OAUTH2_CLIENT_ID= +OAUTH2_CLIENT_SECRET= +OAUTH2_REDIRECT_URL=https://wg-gen-web-demo.127-0-0-1.fr + +# example with google +OAUTH2_PROVIDER_NAME=google +OAUTH2_PROVIDER= +OAUTH2_CLIENT_ID= +OAUTH2_CLIENT_SECRET= +OAUTH2_REDIRECT_URL= + +# example with github +OAUTH2_PROVIDER_NAME=github +OAUTH2_PROVIDER= +OAUTH2_CLIENT_ID= +OAUTH2_CLIENT_SECRET= +OAUTH2_REDIRECT_URL= + +# set provider name to fake to disable auth, also the default +OAUTH2_PROVIDER_NAME=fake diff --git a/api/api.go b/api/api.go index c1bba54..8063cec 100644 --- a/api/api.go +++ b/api/api.go @@ -2,244 +2,12 @@ package api import ( "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" - "github.com/skip2/go-qrcode" - "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/core" - "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/model" - "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/template" - "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/version" - "net/http" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/api/v1" ) -// ApplyRoutes applies router to gin Router -func ApplyRoutes(r *gin.Engine) { - client := r.Group("/api/v1.0/client") +func ApplyRoutes(r *gin.Engine, private bool) { + api := r.Group("/api") { - - client.POST("", createClient) - client.GET("/:id", readClient) - client.PATCH("/:id", updateClient) - client.DELETE("/:id", deleteClient) - client.GET("", readClients) - client.GET("/:id/config", configClient) - client.GET("/:id/email", emailClient) - } - - server := r.Group("/api/v1.0/server") - { - server.GET("", readServer) - server.PATCH("", updateServer) - server.GET("/config", configServer) - server.GET("/version", versionStr) + apiv1.ApplyRoutes(api, private) } } - -func createClient(c *gin.Context) { - var data model.Client - - if err := c.ShouldBindJSON(&data); err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to bind") - c.AbortWithStatus(http.StatusUnprocessableEntity) - return - } - - client, err := core.CreateClient(&data) - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to create client") - c.AbortWithStatus(http.StatusInternalServerError) - return - } - - c.JSON(http.StatusOK, client) -} - -func readClient(c *gin.Context) { - id := c.Param("id") - - client, err := core.ReadClient(id) - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to read client") - c.AbortWithStatus(http.StatusInternalServerError) - return - } - - c.JSON(http.StatusOK, client) -} - -func updateClient(c *gin.Context) { - var data model.Client - id := c.Param("id") - - if err := c.ShouldBindJSON(&data); err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to bind") - c.AbortWithStatus(http.StatusUnprocessableEntity) - return - } - - client, err := core.UpdateClient(id, &data) - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to update client") - c.AbortWithStatus(http.StatusInternalServerError) - return - } - - c.JSON(http.StatusOK, client) -} - -func deleteClient(c *gin.Context) { - id := c.Param("id") - - err := core.DeleteClient(id) - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to remove client") - c.AbortWithStatus(http.StatusInternalServerError) - return - } - - c.JSON(http.StatusOK, gin.H{}) -} - -func readClients(c *gin.Context) { - clients, err := core.ReadClients() - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to list clients") - c.AbortWithStatus(http.StatusInternalServerError) - return - } - - c.JSON(http.StatusOK, clients) -} - -func configClient(c *gin.Context) { - configData, err := core.ReadClientConfig(c.Param("id")) - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to read client config") - c.AbortWithStatus(http.StatusInternalServerError) - return - } - - formatQr := c.DefaultQuery("qrcode", "false") - if formatQr == "false" { - // return config as txt file - c.Header("Content-Disposition", "attachment; filename=wg0.conf") - c.Data(http.StatusOK, "application/config", configData) - return - } - // return config as png qrcode - png, err := qrcode.Encode(string(configData), qrcode.Medium, 250) - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to create qrcode") - c.AbortWithStatus(http.StatusInternalServerError) - return - } - c.Data(http.StatusOK, "image/png", png) - return -} - -func emailClient(c *gin.Context) { - id := c.Param("id") - - err := core.EmailClient(id) - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to send email to client") - c.AbortWithStatus(http.StatusInternalServerError) - return - } - - c.JSON(http.StatusOK, gin.H{}) -} - -func readServer(c *gin.Context) { - client, err := core.ReadServer() - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to read client") - c.AbortWithStatus(http.StatusInternalServerError) - return - } - - c.JSON(http.StatusOK, client) -} - -func updateServer(c *gin.Context) { - var data model.Server - - if err := c.ShouldBindJSON(&data); err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to bind") - c.AbortWithStatus(http.StatusUnprocessableEntity) - return - } - - client, err := core.UpdateServer(&data) - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to update client") - c.AbortWithStatus(http.StatusInternalServerError) - return - } - - c.JSON(http.StatusOK, client) -} - -func configServer(c *gin.Context) { - clients, err := core.ReadClients() - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to read clients") - c.AbortWithStatus(http.StatusUnprocessableEntity) - return - } - - server, err := core.ReadServer() - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to read server") - c.AbortWithStatus(http.StatusUnprocessableEntity) - return - } - - configData, err := template.DumpServerWg(clients, server) - if err != nil { - log.WithFields(log.Fields{ - "err": err, - }).Error("failed to dump wg config") - c.AbortWithStatus(http.StatusUnprocessableEntity) - return - } - - // return config as txt file - c.Header("Content-Disposition", "attachment; filename=wg0.conf") - c.Data(http.StatusOK, "application/config", configData) -} - -func versionStr(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{ - "version": version.Version, - }) -} diff --git a/api/v1/auth/auth.go b/api/v1/auth/auth.go new file mode 100644 index 0000000..66fcd0a --- /dev/null +++ b/api/v1/auth/auth.go @@ -0,0 +1,134 @@ +package auth + +import ( + "github.com/gin-gonic/gin" + "github.com/patrickmn/go-cache" + log "github.com/sirupsen/logrus" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/auth" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/model" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/util" + "golang.org/x/oauth2" + "net/http" + "time" +) + +// ApplyRoutes applies router to gin Router +func ApplyRoutes(r *gin.RouterGroup) { + g := r.Group("/auth") + { + g.GET("/oauth2_url", oauth2_url) + g.POST("/oauth2_exchange", oauth2_exchange) + g.GET("/user", user) + g.GET("/logout", logout) + } +} + +/* + * generate redirect url to get OAuth2 code or let client know that OAuth2 is disabled + */ +func oauth2_url(c *gin.Context) { + cacheDb := c.MustGet("cache").(*cache.Cache) + + state, err := util.GenerateRandomString(32) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to generate state random string") + c.AbortWithStatus(http.StatusInternalServerError) + } + + clientId, err := util.GenerateRandomString(32) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to generate state random string") + c.AbortWithStatus(http.StatusInternalServerError) + } + // save clientId and state so we can retrieve for verification + cacheDb.Set(clientId, state, 5*time.Minute) + + oauth2Client := c.MustGet("oauth2Client").(auth.Auth) + + data := &model.Auth{ + Oauth2: true, + ClientId: clientId, + State: state, + CodeUrl: oauth2Client.CodeUrl(state), + } + + c.JSON(http.StatusOK, data) +} + +/* + * exchange code and get user infos, if OAuth2 is disable just send fake data + */ +func oauth2_exchange(c *gin.Context) { + var loginVals model.Auth + if err := c.ShouldBind(&loginVals); err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("code and state fields are missing") + c.AbortWithStatus(http.StatusUnprocessableEntity) + return + } + + cacheDb := c.MustGet("cache").(*cache.Cache) + savedState, exists := cacheDb.Get(loginVals.ClientId) + + if !exists || savedState != loginVals.State { + log.WithFields(log.Fields{ + "state": loginVals.State, + "savedState": savedState, + }).Error("saved state and client provided state mismatch") + c.AbortWithStatus(http.StatusBadRequest) + return + } + oauth2Client := c.MustGet("oauth2Client").(auth.Auth) + + oauth2Token, err := oauth2Client.Exchange(loginVals.Code) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to exchange code for token") + c.AbortWithStatus(http.StatusBadRequest) + return + } + + cacheDb.Delete(loginVals.ClientId) + cacheDb.Set(oauth2Token.AccessToken, oauth2Token, cache.DefaultExpiration) + + c.JSON(http.StatusOK, oauth2Token.AccessToken) +} + +func logout(c *gin.Context) { + cacheDb := c.MustGet("cache").(*cache.Cache) + cacheDb.Delete(c.Request.Header.Get(util.AuthTokenHeaderName)) + c.JSON(http.StatusOK, gin.H{}) +} + +func user(c *gin.Context) { + cacheDb := c.MustGet("cache").(*cache.Cache) + oauth2Token, exists := cacheDb.Get(c.Request.Header.Get(util.AuthTokenHeaderName)) + + if exists && oauth2Token.(*oauth2.Token).AccessToken == c.Request.Header.Get(util.AuthTokenHeaderName) { + oauth2Client := c.MustGet("oauth2Client").(auth.Auth) + user, err := oauth2Client.UserInfo(oauth2Token.(*oauth2.Token)) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to get user from oauth2 AccessToken") + c.AbortWithStatus(http.StatusBadRequest) + return + } + + c.JSON(http.StatusOK, user) + return + } + + log.WithFields(log.Fields{ + "exists": exists, + util.AuthTokenHeaderName: c.Request.Header.Get(util.AuthTokenHeaderName), + }).Error("oauth2 AccessToken is not recognized") + + c.AbortWithStatus(http.StatusUnauthorized) +} diff --git a/api/v1/client/client.go b/api/v1/client/client.go new file mode 100644 index 0000000..13be7ba --- /dev/null +++ b/api/v1/client/client.go @@ -0,0 +1,190 @@ +package client + +import ( + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "github.com/skip2/go-qrcode" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/auth" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/core" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/model" + "golang.org/x/oauth2" + "net/http" +) + +// ApplyRoutes applies router to gin Router +func ApplyRoutes(r *gin.RouterGroup) { + g := r.Group("/client") + { + + g.POST("", createClient) + g.GET("/:id", readClient) + g.PATCH("/:id", updateClient) + g.DELETE("/:id", deleteClient) + g.GET("", readClients) + g.GET("/:id/config", configClient) + g.GET("/:id/email", emailClient) + } +} + +func createClient(c *gin.Context) { + var data model.Client + + if err := c.ShouldBindJSON(&data); err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to bind") + c.AbortWithStatus(http.StatusUnprocessableEntity) + return + } + + // get creation user from token and add to client infos + oauth2Token := c.MustGet("oauth2Token").(*oauth2.Token) + oauth2Client := c.MustGet("oauth2Client").(auth.Auth) + user, err := oauth2Client.UserInfo(oauth2Token) + if err != nil { + log.WithFields(log.Fields{ + "oauth2Token": oauth2Token, + "err": err, + }).Error("failed to get user with oauth token") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + data.CreatedBy = user.Name + + client, err := core.CreateClient(&data) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to create client") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + c.JSON(http.StatusOK, client) +} + +func readClient(c *gin.Context) { + id := c.Param("id") + + client, err := core.ReadClient(id) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to read client") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + c.JSON(http.StatusOK, client) +} + +func updateClient(c *gin.Context) { + var data model.Client + id := c.Param("id") + + if err := c.ShouldBindJSON(&data); err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to bind") + c.AbortWithStatus(http.StatusUnprocessableEntity) + return + } + + // get update user from token and add to client infos + oauth2Token := c.MustGet("oauth2Token").(*oauth2.Token) + oauth2Client := c.MustGet("oauth2Client").(auth.Auth) + user, err := oauth2Client.UserInfo(oauth2Token) + if err != nil { + log.WithFields(log.Fields{ + "oauth2Token": oauth2Token, + "err": err, + }).Error("failed to get user with oauth token") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + data.UpdatedBy = user.Name + + client, err := core.UpdateClient(id, &data) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to update client") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + c.JSON(http.StatusOK, client) +} + +func deleteClient(c *gin.Context) { + id := c.Param("id") + + err := core.DeleteClient(id) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to remove client") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + c.JSON(http.StatusOK, gin.H{}) +} + +func readClients(c *gin.Context) { + clients, err := core.ReadClients() + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to list clients") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + c.JSON(http.StatusOK, clients) +} + +func configClient(c *gin.Context) { + configData, err := core.ReadClientConfig(c.Param("id")) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to read client config") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + formatQr := c.DefaultQuery("qrcode", "false") + if formatQr == "false" { + // return config as txt file + c.Header("Content-Disposition", "attachment; filename=wg0.conf") + c.Data(http.StatusOK, "application/config", configData) + return + } + // return config as png qrcode + png, err := qrcode.Encode(string(configData), qrcode.Medium, 250) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to create qrcode") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + c.Data(http.StatusOK, "image/png", png) + return +} + +func emailClient(c *gin.Context) { + id := c.Param("id") + + err := core.EmailClient(id) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to send email to client") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + c.JSON(http.StatusOK, gin.H{}) +} diff --git a/api/v1/server/server.go b/api/v1/server/server.go new file mode 100644 index 0000000..158deb9 --- /dev/null +++ b/api/v1/server/server.go @@ -0,0 +1,113 @@ +package server + +import ( + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/auth" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/core" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/model" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/template" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/version" + "golang.org/x/oauth2" + "net/http" +) + +// ApplyRoutes applies router to gin Router +func ApplyRoutes(r *gin.RouterGroup) { + g := r.Group("/server") + { + g.GET("", readServer) + g.PATCH("", updateServer) + g.GET("/config", configServer) + g.GET("/version", versionStr) + } +} + +func readServer(c *gin.Context) { + client, err := core.ReadServer() + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to read client") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + c.JSON(http.StatusOK, client) +} + +func updateServer(c *gin.Context) { + var data model.Server + + if err := c.ShouldBindJSON(&data); err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to bind") + c.AbortWithStatus(http.StatusUnprocessableEntity) + return + } + + // get update user from token and add to server infos + oauth2Token := c.MustGet("oauth2Token").(*oauth2.Token) + oauth2Client := c.MustGet("oauth2Client").(auth.Auth) + user, err := oauth2Client.UserInfo(oauth2Token) + if err != nil { + log.WithFields(log.Fields{ + "oauth2Token": oauth2Token, + "err": err, + }).Error("failed to get user with oauth token") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + data.UpdatedBy = user.Name + + server, err := core.UpdateServer(&data) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to update client") + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + c.JSON(http.StatusOK, server) +} + +func configServer(c *gin.Context) { + clients, err := core.ReadClients() + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to read clients") + c.AbortWithStatus(http.StatusUnprocessableEntity) + return + } + + server, err := core.ReadServer() + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to read server") + c.AbortWithStatus(http.StatusUnprocessableEntity) + return + } + + configData, err := template.DumpServerWg(clients, server) + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Error("failed to dump wg config") + c.AbortWithStatus(http.StatusUnprocessableEntity) + return + } + + // return config as txt file + c.Header("Content-Disposition", "attachment; filename=wg0.conf") + c.Data(http.StatusOK, "application/config", configData) +} + +func versionStr(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{ + "version": version.Version, + }) +} diff --git a/api/v1/v1.go b/api/v1/v1.go new file mode 100644 index 0000000..ce1339f --- /dev/null +++ b/api/v1/v1.go @@ -0,0 +1,21 @@ +package apiv1 + +import ( + "github.com/gin-gonic/gin" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/api/v1/auth" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/api/v1/client" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/api/v1/server" +) + +func ApplyRoutes(r *gin.RouterGroup, private bool) { + v1 := r.Group("/v1.0") + { + if private { + client.ApplyRoutes(v1) + server.ApplyRoutes(v1) + } else { + auth.ApplyRoutes(v1) + + } + } +} diff --git a/auth/auth.go b/auth/auth.go new file mode 100644 index 0000000..d4dadae --- /dev/null +++ b/auth/auth.go @@ -0,0 +1,13 @@ +package auth + +import ( + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/model" + "golang.org/x/oauth2" +) + +type Auth interface { + Setup() error + CodeUrl(state string) string + Exchange(code string) (*oauth2.Token, error) + UserInfo(oauth2Token *oauth2.Token) (*model.User, error) +} diff --git a/auth/fake/fake.go b/auth/fake/fake.go new file mode 100644 index 0000000..0ebe8d8 --- /dev/null +++ b/auth/fake/fake.go @@ -0,0 +1,47 @@ +package fake + +import ( + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/model" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/util" + "golang.org/x/oauth2" + "time" +) + +type Fake struct{} + +// Setup validate provider +func (o *Fake) Setup() error { + return nil +} + +// CodeUrl get url to redirect client for auth +func (o *Fake) CodeUrl(state string) string { + return "_magic_string_fake_auth_no_redirect_" +} + +// Exchange exchange code for Oauth2 token +func (o *Fake) Exchange(code string) (*oauth2.Token, error) { + rand, err := util.GenerateRandomString(32) + if err != nil { + return nil, err + } + + return &oauth2.Token{ + AccessToken: rand, + TokenType: "", + RefreshToken: "", + Expiry: time.Time{}, + }, nil +} + +// UserInfo get token user +func (o *Fake) UserInfo(oauth2Token *oauth2.Token) (*model.User, error) { + return &model.User{ + Sub: "unknown", + Name: "Unknown", + Email: "unknown", + Profile: "unknown", + Issuer: "unknown", + IssuedAt: time.Time{}, + }, nil +} diff --git a/auth/github/github.go b/auth/github/github.go new file mode 100644 index 0000000..d2e73c2 --- /dev/null +++ b/auth/github/github.go @@ -0,0 +1 @@ +package github diff --git a/auth/google/goolge.go b/auth/google/goolge.go new file mode 100644 index 0000000..71664db --- /dev/null +++ b/auth/google/goolge.go @@ -0,0 +1 @@ +package google diff --git a/auth/oauth2oidc/oauth2oidc.go b/auth/oauth2oidc/oauth2oidc.go new file mode 100644 index 0000000..b50444a --- /dev/null +++ b/auth/oauth2oidc/oauth2oidc.go @@ -0,0 +1,108 @@ +package oauth2oidc + +import ( + "context" + "fmt" + "github.com/coreos/go-oidc" + log "github.com/sirupsen/logrus" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/model" + "golang.org/x/oauth2" + "os" +) + +type Oauth2idc struct{} + +var ( + oauth2Config *oauth2.Config + oidcProvider *oidc.Provider + oidcIDTokenVerifier *oidc.IDTokenVerifier +) + +// Setup validate provider +func (o *Oauth2idc) Setup() error { + var err error + + oidcProvider, err = oidc.NewProvider(context.TODO(), os.Getenv("OAUTH2_PROVIDER")) + if err != nil { + return err + } + + oidcIDTokenVerifier = oidcProvider.Verifier(&oidc.Config{ + ClientID: os.Getenv("OAUTH2_CLIENT_ID"), + }) + + oauth2Config = &oauth2.Config{ + ClientID: os.Getenv("OAUTH2_CLIENT_ID"), + ClientSecret: os.Getenv("OAUTH2_CLIENT_SECRET"), + RedirectURL: os.Getenv("OAUTH2_REDIRECT_URL"), + Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, + Endpoint: oidcProvider.Endpoint(), + } + + return nil +} + +// CodeUrl get url to redirect client for auth +func (o *Oauth2idc) CodeUrl(state string) string { + return oauth2Config.AuthCodeURL(state) +} + +// Exchange exchange code for Oauth2 token +func (o *Oauth2idc) Exchange(code string) (*oauth2.Token, error) { + oauth2Token, err := oauth2Config.Exchange(context.TODO(), code) + if err != nil { + return nil, err + } + + return oauth2Token, nil +} + +// UserInfo get token user +func (o *Oauth2idc) UserInfo(oauth2Token *oauth2.Token) (*model.User, error) { + rawIDToken, ok := oauth2Token.Extra("id_token").(string) + if !ok { + return nil, fmt.Errorf("no id_token field in oauth2 token") + } + + iDToken, err := oidcIDTokenVerifier.Verify(context.TODO(), rawIDToken) + if err != nil { + return nil, err + } + + userInfo, err := oidcProvider.UserInfo(context.TODO(), oauth2.StaticTokenSource(oauth2Token)) + if err != nil { + return nil, err + } + + type UserInfo struct { + Subject string `json:"sub"` + Profile string `json:"profile"` + Email string `json:"email"` + EmailVerified bool `json:"email_verified"` + + claims []byte + } + + // ID Token payload is just JSON + var claims map[string]interface{} + if err := userInfo.Claims(&claims); err != nil { + return nil, fmt.Errorf("failed to get id token claims: %s", err) + } + + // get some infos about user + user := &model.User{} + user.Sub = userInfo.Subject + user.Email = userInfo.Email + user.Profile = userInfo.Profile + + if v, found := claims["name"]; found && v != nil { + user.Name = v.(string) + } else { + log.Error("name not found in user info claims") + } + + user.Issuer = iDToken.Issuer + user.IssuedAt = iDToken.IssuedAt + + return user, nil +} diff --git a/cmd/wg-gen-web/main.go b/cmd/wg-gen-web/main.go index cdb044e..1422208 100644 --- a/cmd/wg-gen-web/main.go +++ b/cmd/wg-gen-web/main.go @@ -7,13 +7,24 @@ import ( "github.com/gin-contrib/static" "github.com/gin-gonic/gin" "github.com/joho/godotenv" + "github.com/patrickmn/go-cache" log "github.com/sirupsen/logrus" "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/api" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/auth" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/auth/fake" + "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/auth/oauth2oidc" "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/core" "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/util" "gitlab.127-0-0-1.fr/vx3r/wg-gen-web/version" + "golang.org/x/oauth2" + "net/http" "os" "path/filepath" + "time" +) + +var ( + cacheDb = cache.New(60*time.Minute, 10*time.Minute) ) func init() { @@ -80,21 +91,88 @@ func main() { // cors middleware config := cors.DefaultConfig() config.AllowAllOrigins = true + config.AddAllowHeaders("Authorization") app.Use(cors.New(config)) // protection middleware app.Use(helmet.Default()) - // no route redirect to frontend app - app.NoRoute(func(c *gin.Context) { - c.Redirect(301, "/index.html") + // add cache storage to gin app + app.Use(func(ctx *gin.Context) { + ctx.Set("cache", cacheDb) + ctx.Next() }) // serve static files app.Use(static.Serve("/", static.LocalFile("./ui/dist", false))) - // apply api router - api.ApplyRoutes(app) + // setup Oauth2 client if enabled + var oauth2Client auth.Auth + + switch os.Getenv("OAUTH2_PROVIDER_NAME") { + case "fake": + log.Warn("Oauth is set to fake, no actual authentication will be performed") + oauth2Client = &fake.Fake{} + err = oauth2Client.Setup() + if err != nil { + log.WithFields(log.Fields{ + "OAUTH2_PROVIDER_NAME": "oauth2oidc", + "err": err, + }).Fatal("failed to setup Oauth2") + } + case "oauth2oidc": + log.Warn("Oauth is set to oauth2oidc, must be RFC implementation on server side") + oauth2Client = &oauth2oidc.Oauth2idc{} + err = oauth2Client.Setup() + if err != nil { + log.WithFields(log.Fields{ + "OAUTH2_PROVIDER_NAME": "oauth2oidc", + "err": err, + }).Fatal("failed to setup Oauth2") + } + default: + log.WithFields(log.Fields{ + "OAUTH2_PROVIDER_NAME": os.Getenv("OAUTH2_PROVIDER_NAME"), + }).Fatal("auth provider name unknown") + } + + if os.Getenv("OAUTH2_ENABLE") == "true" { + oauth2Client = &oauth2oidc.Oauth2idc{} + err = oauth2Client.Setup() + if err != nil { + log.WithFields(log.Fields{ + "err": err, + }).Fatal("failed to setup Oauth2") + } + } + app.Use(func(ctx *gin.Context) { + ctx.Set("oauth2Client", oauth2Client) + ctx.Next() + }) + + // apply api routes public + api.ApplyRoutes(app, false) + + // simple middleware to check auth + app.Use(func(c *gin.Context) { + cacheDb := c.MustGet("cache").(*cache.Cache) + + token := c.Request.Header.Get(util.AuthTokenHeaderName) + + oauth2Token, exists := cacheDb.Get(token) + if exists && oauth2Token.(*oauth2.Token).AccessToken == token { + // will be accessible in auth endpoints + c.Set("oauth2Token", oauth2Token) + c.Next() + return + } + + c.AbortWithStatus(http.StatusUnauthorized) + return + }) + + // apply api router private + api.ApplyRoutes(app, true) err = app.Run(fmt.Sprintf("%s:%s", os.Getenv("SERVER"), os.Getenv("PORT"))) if err != nil { diff --git a/go.mod b/go.mod index cf77582..1d31fa6 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,26 @@ module gitlab.127-0-0-1.fr/vx3r/wg-gen-web go 1.14 require ( + github.com/appleboy/gin-jwt/v2 v2.6.3 // indirect + github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect + github.com/coreos/go-oidc v2.2.1+incompatible github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e github.com/gin-contrib/cors v1.3.1 + github.com/gin-contrib/sessions v0.0.3 github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2 + github.com/gin-gonic/contrib v0.0.0-20191209060500-d6e26eeaa607 // indirect github.com/gin-gonic/gin v1.6.2 + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect + github.com/gorilla/sessions v1.2.0 // indirect github.com/joho/godotenv v1.3.0 + github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect github.com/satori/go.uuid v1.2.0 github.com/sirupsen/logrus v1.5.0 github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086 + golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200324154536-ceff61240acf gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df + gopkg.in/square/go-jose.v2 v2.5.0 // indirect ) diff --git a/model/auth.go b/model/auth.go new file mode 100644 index 0000000..941dfee --- /dev/null +++ b/model/auth.go @@ -0,0 +1,9 @@ +package model + +type Auth struct { + Oauth2 bool `json:"oauth2"` + ClientId string `json:"clientId"` + Code string `json:"code"` + State string `json:"state"` + CodeUrl string `json:"codeUrl"` +} diff --git a/model/client.go b/model/client.go index 78cda45..4a40b27 100644 --- a/model/client.go +++ b/model/client.go @@ -18,6 +18,8 @@ type Client struct { Address []string `json:"address"` PrivateKey string `json:"privateKey"` PublicKey string `json:"publicKey"` + CreatedBy string `json:"createdBy"` + UpdatedBy string `json:"updatedBy"` Created time.Time `json:"created"` Updated time.Time `json:"updated"` } diff --git a/model/server.go b/model/server.go index 592aa36..eb45782 100644 --- a/model/server.go +++ b/model/server.go @@ -21,6 +21,7 @@ type Server struct { PostUp string `json:"postUp"` PreDown string `json:"preDown"` PostDown string `json:"postDown"` + UpdatedBy string `json:"updatedBy"` Created time.Time `json:"created"` Updated time.Time `json:"updated"` } diff --git a/model/user.go b/model/user.go new file mode 100644 index 0000000..852123f --- /dev/null +++ b/model/user.go @@ -0,0 +1,12 @@ +package model + +import "time" + +type User struct { + Sub string `json:"sub"` + Name string `json:"name"` + Email string `json:"email"` + Profile string `json:"profile"` + Issuer string `json:"issuer"` + IssuedAt time.Time `json:"issuedAt"` +} diff --git a/ui/package-lock.json b/ui/package-lock.json index c3a8613..8aa703e 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -109,19 +109,19 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -134,7 +134,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1573280577145&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -143,7 +143,7 @@ }, "supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-2.0.0.tgz?cache=0&sync_timestamp=1569557363805&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } @@ -339,7 +339,7 @@ }, "yallist": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true } @@ -608,7 +608,7 @@ }, "alphanum-sort": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/alphanum-sort/download/alphanum-sort-1.0.2.tgz", "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", "dev": true }, @@ -620,7 +620,7 @@ }, "ansi-html": { "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "resolved": "https://registry.npm.taobao.org/ansi-html/download/ansi-html-0.0.7.tgz", "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", "dev": true }, @@ -641,7 +641,7 @@ }, "any-promise": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "resolved": "https://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz", "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", "dev": true }, @@ -678,7 +678,7 @@ }, "arr-diff": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/arr-diff/download/arr-diff-4.0.0.tgz", "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", "dev": true }, @@ -690,19 +690,19 @@ }, "arr-union": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/arr-union/download/arr-union-3.1.0.tgz", "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, "array-flatten": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz?cache=0&sync_timestamp=1574313492546&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Farray-flatten%2Fdownload%2Farray-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", "dev": true }, "array-union": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/array-union/download/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { @@ -711,13 +711,13 @@ }, "array-uniq": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "resolved": "https://registry.npm.taobao.org/array-uniq/download/array-uniq-1.0.3.tgz", "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", "dev": true }, "array-unique": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "resolved": "https://registry.npm.taobao.org/array-unique/download/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, @@ -753,13 +753,13 @@ "dependencies": { "inherits": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.1.tgz", "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", "dev": true }, "util": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "https://registry.npm.taobao.org/util/download/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -770,13 +770,13 @@ }, "assert-plus": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/assert-plus/download/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, "assign-symbols": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/assign-symbols/download/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, @@ -803,7 +803,7 @@ }, "asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "resolved": "https://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, @@ -830,7 +830,7 @@ }, "aws-sign2": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "resolved": "https://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz", "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", "dev": true }, @@ -894,7 +894,7 @@ "dependencies": { "define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { @@ -940,13 +940,13 @@ }, "batch": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "resolved": "https://registry.npm.taobao.org/batch/download/batch-0.6.1.tgz", "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", "dev": true }, "bcrypt-pbkdf": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "dev": true, "requires": { @@ -1018,7 +1018,7 @@ }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, @@ -1032,7 +1032,7 @@ }, "bonjour": { "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "resolved": "https://registry.npm.taobao.org/bonjour/download/bonjour-3.5.0.tgz", "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", "dev": true, "requires": { @@ -1054,7 +1054,7 @@ }, "boolbase": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/boolbase/download/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, @@ -1088,7 +1088,7 @@ "dependencies": { "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { @@ -1099,7 +1099,7 @@ }, "brorand": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/brorand/download/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", "dev": true }, @@ -1142,7 +1142,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/browserify-rsa/download/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { @@ -1152,7 +1152,7 @@ }, "browserify-sign": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "resolved": "https://registry.npm.taobao.org/browserify-sign/download/browserify-sign-4.0.4.tgz", "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", "dev": true, "requires": { @@ -1217,13 +1217,13 @@ }, "buffer-xor": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "resolved": "https://registry.npm.taobao.org/buffer-xor/download/buffer-xor-1.0.3.tgz", "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", "dev": true }, "builtin-status-codes": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/builtin-status-codes/download/builtin-status-codes-3.0.0.tgz", "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", "dev": true }, @@ -1300,13 +1300,13 @@ }, "call-me-maybe": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/call-me-maybe/download/call-me-maybe-1.0.1.tgz", "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", "dev": true }, "caller-callsite": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/caller-callsite/download/caller-callsite-2.0.0.tgz?cache=0&sync_timestamp=1562696843228&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcaller-callsite%2Fdownload%2Fcaller-callsite-2.0.0.tgz", "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", "dev": true, "requires": { @@ -1315,7 +1315,7 @@ }, "caller-path": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/caller-path/download/caller-path-2.0.0.tgz?cache=0&sync_timestamp=1574395542397&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcaller-path%2Fdownload%2Fcaller-path-2.0.0.tgz", "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", "dev": true, "requires": { @@ -1324,13 +1324,13 @@ }, "callsites": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/callsites/download/callsites-2.0.0.tgz", "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", "dev": true }, "camel-case": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/camel-case/download/camel-case-3.0.0.tgz", "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", "dev": true, "requires": { @@ -1370,7 +1370,7 @@ }, "caseless": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "resolved": "https://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, @@ -1498,7 +1498,7 @@ "dependencies": { "define-property": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { @@ -1524,7 +1524,7 @@ }, "cli-cursor": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/cli-cursor/download/cli-cursor-2.1.0.tgz", "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { @@ -1654,7 +1654,7 @@ }, "clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "resolved": "https://registry.npm.taobao.org/clone/download/clone-1.0.4.tgz", "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", "dev": true }, @@ -1682,13 +1682,13 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/code-point-at/download/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "collection-visit": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/collection-visit/download/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { @@ -1717,7 +1717,7 @@ }, "color-name": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, @@ -1748,7 +1748,7 @@ }, "commondir": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/commondir/download/commondir-1.0.1.tgz", "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, @@ -1784,7 +1784,7 @@ "dependencies": { "bytes": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", "dev": true }, @@ -1799,7 +1799,7 @@ }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, @@ -1852,7 +1852,7 @@ }, "constants-browserify": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/constants-browserify/download/constants-browserify-1.0.0.tgz", "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", "dev": true }, @@ -1887,7 +1887,7 @@ }, "cookie-signature": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "resolved": "https://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", "dev": true }, @@ -1907,7 +1907,7 @@ }, "copy-descriptor": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz", "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, @@ -1953,7 +1953,7 @@ }, "globby": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/globby/download/globby-7.1.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglobby%2Fdownload%2Fglobby-7.1.1.tgz", "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", "dev": true, "requires": { @@ -1967,7 +1967,7 @@ "dependencies": { "pify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/pify/download/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true } @@ -2047,7 +2047,7 @@ }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, @@ -2154,7 +2154,7 @@ }, "css-color-names": { "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "resolved": "https://registry.npm.taobao.org/css-color-names/download/css-color-names-0.0.4.tgz", "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", "dev": true }, @@ -2306,13 +2306,13 @@ }, "cssnano-util-get-arguments": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/cssnano-util-get-arguments/download/cssnano-util-get-arguments-4.0.0.tgz", "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", "dev": true }, "cssnano-util-get-match": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/cssnano-util-get-match/download/cssnano-util-get-match-4.0.0.tgz", "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", "dev": true }, @@ -2360,13 +2360,13 @@ }, "cyclist": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/cyclist/download/cyclist-1.0.1.tgz", "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", "dev": true }, "dashdash": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "resolved": "https://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { @@ -2390,13 +2390,13 @@ }, "decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "resolved": "https://registry.npm.taobao.org/decamelize/download/decamelize-1.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdecamelize%2Fdownload%2Fdecamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "decode-uri-component": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "resolved": "https://registry.npm.taobao.org/decode-uri-component/download/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, @@ -2537,7 +2537,7 @@ }, "defaults": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "resolved": "https://registry.npm.taobao.org/defaults/download/defaults-1.0.3.tgz", "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "dev": true, "requires": { @@ -2611,7 +2611,7 @@ "dependencies": { "globby": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/globby/download/globby-6.1.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglobby%2Fdownload%2Fglobby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { @@ -2624,7 +2624,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npm.taobao.org/pify/download/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -2640,13 +2640,13 @@ }, "delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, "depd": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", "dev": true }, @@ -2662,7 +2662,7 @@ }, "destroy": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "resolved": "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", "dev": true }, @@ -2694,7 +2694,7 @@ }, "dns-equal": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/dns-equal/download/dns-equal-1.0.0.tgz", "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", "dev": true }, @@ -2710,7 +2710,7 @@ }, "dns-txt": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/dns-txt/download/dns-txt-2.0.2.tgz", "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", "dev": true, "requires": { @@ -2798,7 +2798,7 @@ }, "duplexer": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/duplexer/download/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", "dev": true }, @@ -2816,13 +2816,13 @@ }, "easy-stack": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/easy-stack/download/easy-stack-1.0.0.tgz", "integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=", "dev": true }, "ecc-jsbn": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "resolved": "https://registry.npm.taobao.org/ecc-jsbn/download/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "dev": true, "requires": { @@ -2832,7 +2832,7 @@ }, "ee-first": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, @@ -2877,7 +2877,7 @@ }, "encodeurl": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "dev": true }, @@ -2978,13 +2978,13 @@ }, "escape-html": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "resolved": "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, "escape-string-regexp": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "resolved": "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, @@ -3021,7 +3021,7 @@ }, "etag": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "resolved": "https://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, @@ -3079,7 +3079,7 @@ }, "expand-brackets": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "resolved": "https://registry.npm.taobao.org/expand-brackets/download/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { @@ -3103,7 +3103,7 @@ }, "define-property": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { @@ -3112,7 +3112,7 @@ }, "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { @@ -3121,7 +3121,7 @@ }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } @@ -3176,7 +3176,7 @@ }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, @@ -3202,7 +3202,7 @@ }, "extend-shallow": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-3.0.2.tgz", "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { @@ -3239,7 +3239,7 @@ "dependencies": { "define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { @@ -3248,7 +3248,7 @@ }, "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { @@ -3288,7 +3288,7 @@ }, "extsprintf": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "resolved": "https://registry.npm.taobao.org/extsprintf/download/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, @@ -3320,7 +3320,7 @@ }, "faye-websocket": { "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "resolved": "https://registry.npm.taobao.org/faye-websocket/download/faye-websocket-0.10.0.tgz", "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", "dev": true, "requires": { @@ -3351,7 +3351,7 @@ }, "fill-range": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { @@ -3363,7 +3363,7 @@ "dependencies": { "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { @@ -3398,7 +3398,7 @@ }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } @@ -3456,13 +3456,13 @@ }, "for-in": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/for-in/download/for-in-1.0.2.tgz", "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, "forever-agent": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "resolved": "https://registry.npm.taobao.org/forever-agent/download/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "dev": true }, @@ -3479,13 +3479,13 @@ }, "forwarded": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "resolved": "https://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz", "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", "dev": true }, "fragment-cache": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "resolved": "https://registry.npm.taobao.org/fragment-cache/download/fragment-cache-0.2.1.tgz", "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { @@ -3494,13 +3494,13 @@ }, "fresh": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "resolved": "https://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", "dev": true }, "from2": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "resolved": "https://registry.npm.taobao.org/from2/download/from2-2.3.0.tgz", "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "dev": true, "requires": { @@ -3530,7 +3530,7 @@ }, "fs-write-stream-atomic": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "resolved": "https://registry.npm.taobao.org/fs-write-stream-atomic/download/fs-write-stream-atomic-1.0.10.tgz", "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", "dev": true, "requires": { @@ -3576,13 +3576,13 @@ }, "get-value": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "resolved": "https://registry.npm.taobao.org/get-value/download/get-value-2.0.6.tgz", "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true }, "getpass": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "resolved": "https://registry.npm.taobao.org/getpass/download/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { @@ -3605,7 +3605,7 @@ }, "glob-parent": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-3.1.0.tgz", "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { @@ -3615,7 +3615,7 @@ "dependencies": { "is-glob": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz", "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { @@ -3626,7 +3626,7 @@ }, "glob-to-regexp": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "resolved": "https://registry.npm.taobao.org/glob-to-regexp/download/glob-to-regexp-0.3.0.tgz", "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", "dev": true }, @@ -3684,7 +3684,7 @@ }, "har-schema": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/har-schema/download/har-schema-2.0.0.tgz", "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", "dev": true }, @@ -3709,7 +3709,7 @@ }, "has-ansi": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/has-ansi/download/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { @@ -3718,7 +3718,7 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true } @@ -3726,7 +3726,7 @@ }, "has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, @@ -3738,7 +3738,7 @@ }, "has-value": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/has-value/download/has-value-1.0.0.tgz", "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { @@ -3749,7 +3749,7 @@ }, "has-values": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/has-values/download/has-values-1.0.0.tgz", "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { @@ -3759,7 +3759,7 @@ "dependencies": { "kind-of": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-4.0.0.tgz?cache=0&sync_timestamp=1579193926808&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fkind-of%2Fdownload%2Fkind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { @@ -3770,7 +3770,7 @@ }, "hash-base": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "resolved": "https://registry.npm.taobao.org/hash-base/download/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "dev": true, "requires": { @@ -3814,7 +3814,7 @@ }, "hmac-drbg": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/hmac-drbg/download/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "dev": true, "requires": { @@ -3837,7 +3837,7 @@ }, "hpack.js": { "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "resolved": "https://registry.npm.taobao.org/hpack.js/download/hpack.js-2.1.6.tgz", "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", "dev": true, "requires": { @@ -3849,13 +3849,13 @@ }, "hsl-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/hsl-regex/download/hsl-regex-1.0.0.tgz", "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", "dev": true }, "hsla-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/hsla-regex/download/hsla-regex-1.0.0.tgz", "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", "dev": true }, @@ -3888,7 +3888,7 @@ }, "html-webpack-plugin": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", + "resolved": "https://registry.npm.taobao.org/html-webpack-plugin/download/html-webpack-plugin-3.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhtml-webpack-plugin%2Fdownload%2Fhtml-webpack-plugin-3.2.0.tgz", "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", "dev": true, "requires": { @@ -3909,13 +3909,13 @@ }, "json5": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "https://registry.npm.taobao.org/json5/download/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", "dev": true }, "loader-utils": { "version": "0.2.17", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-0.2.17.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Floader-utils%2Fdownload%2Floader-utils-0.2.17.tgz", "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", "dev": true, "requires": { @@ -3972,7 +3972,7 @@ }, "http-deceiver": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "resolved": "https://registry.npm.taobao.org/http-deceiver/download/http-deceiver-1.2.7.tgz", "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", "dev": true }, @@ -3991,7 +3991,7 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true } @@ -3999,7 +3999,7 @@ }, "http-parser-js": { "version": "0.4.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "resolved": "https://registry.npm.taobao.org/http-parser-js/download/http-parser-js-0.4.10.tgz", "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", "dev": true }, @@ -4028,7 +4028,7 @@ }, "http-signature": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "resolved": "https://registry.npm.taobao.org/http-signature/download/http-signature-1.2.0.tgz?cache=0&sync_timestamp=1572997318670&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-signature%2Fdownload%2Fhttp-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, "requires": { @@ -4039,7 +4039,7 @@ }, "https-browserify": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/https-browserify/download/https-browserify-1.0.0.tgz", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "dev": true }, @@ -4075,7 +4075,7 @@ }, "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "resolved": "https://registry.npm.taobao.org/iferr/download/iferr-0.1.5.tgz", "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", "dev": true }, @@ -4087,7 +4087,7 @@ }, "import-cwd": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/import-cwd/download/import-cwd-2.1.0.tgz", "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", "dev": true, "requires": { @@ -4096,7 +4096,7 @@ }, "import-fresh": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/import-fresh/download/import-fresh-2.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimport-fresh%2Fdownload%2Fimport-fresh-2.0.0.tgz", "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", "dev": true, "requires": { @@ -4106,7 +4106,7 @@ }, "import-from": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/import-from/download/import-from-2.1.0.tgz", "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", "dev": true, "requires": { @@ -4179,7 +4179,7 @@ }, "imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "resolved": "https://registry.npm.taobao.org/imurmurhash/download/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, @@ -4191,7 +4191,7 @@ }, "indexes-of": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/indexes-of/download/indexes-of-1.0.1.tgz", "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", "dev": true }, @@ -4253,7 +4253,7 @@ }, "ip": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "resolved": "https://registry.npm.taobao.org/ip/download/ip-1.1.5.tgz", "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", "dev": true }, @@ -4270,13 +4270,13 @@ }, "is-absolute-url": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/is-absolute-url/download/is-absolute-url-2.1.0.tgz?cache=0&sync_timestamp=1569735663940&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-absolute-url%2Fdownload%2Fis-absolute-url-2.1.0.tgz", "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", "dev": true }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -4285,7 +4285,7 @@ "dependencies": { "kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz?cache=0&sync_timestamp=1579193926808&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fkind-of%2Fdownload%2Fkind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { @@ -4302,7 +4302,7 @@ }, "is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "resolved": "https://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, @@ -4337,7 +4337,7 @@ }, "is-color-stop": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/is-color-stop/download/is-color-stop-1.1.0.tgz", "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", "dev": true, "requires": { @@ -4351,7 +4351,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -4360,7 +4360,7 @@ "dependencies": { "kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz?cache=0&sync_timestamp=1579193926808&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fkind-of%2Fdownload%2Fkind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { @@ -4396,13 +4396,13 @@ }, "is-directory": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "resolved": "https://registry.npm.taobao.org/is-directory/download/is-directory-0.3.1.tgz", "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", "dev": true }, "is-extendable": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz", "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true }, @@ -4414,7 +4414,7 @@ }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, @@ -4429,7 +4429,7 @@ }, "is-number": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/is-number/download/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { @@ -4438,7 +4438,7 @@ "dependencies": { "kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz?cache=0&sync_timestamp=1579193926808&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fkind-of%2Fdownload%2Fkind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { @@ -4479,7 +4479,7 @@ }, "is-plain-obj": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/is-plain-obj/download/is-plain-obj-1.1.0.tgz?cache=0&sync_timestamp=1579602956062&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-plain-obj%2Fdownload%2Fis-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", "dev": true }, @@ -4509,7 +4509,7 @@ }, "is-stream": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/is-stream/download/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, @@ -4533,7 +4533,7 @@ }, "is-typedarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, @@ -4545,19 +4545,19 @@ }, "is-wsl": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/is-wsl/download/is-wsl-1.1.0.tgz?cache=0&sync_timestamp=1569219566107&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-wsl%2Fdownload%2Fis-wsl-1.1.0.tgz", "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", "dev": true }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, "isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, @@ -4569,7 +4569,7 @@ }, "isstream": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "resolved": "https://registry.npm.taobao.org/isstream/download/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, @@ -4608,13 +4608,13 @@ }, "js-message": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz", + "resolved": "https://registry.npm.taobao.org/js-message/download/js-message-1.0.5.tgz?cache=0&sync_timestamp=1575284239628&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-message%2Fdownload%2Fjs-message-1.0.5.tgz", "integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=", "dev": true }, "js-queue": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/js-queue/download/js-queue-2.0.0.tgz", "integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=", "dev": true, "requires": { @@ -4639,7 +4639,7 @@ }, "jsbn": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/jsbn/download/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, @@ -4651,7 +4651,7 @@ }, "json-schema": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "resolved": "https://registry.npm.taobao.org/json-schema/download/json-schema-0.2.3.tgz", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "dev": true }, @@ -4663,7 +4663,7 @@ }, "json-stringify-safe": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, @@ -4684,7 +4684,7 @@ }, "jsonfile": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, "requires": { @@ -4693,7 +4693,7 @@ }, "jsprim": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "resolved": "https://registry.npm.taobao.org/jsprim/download/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "dev": true, "requires": { @@ -4745,7 +4745,7 @@ }, "lines-and-columns": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "resolved": "https://registry.npm.taobao.org/lines-and-columns/download/lines-and-columns-1.1.6.tgz", "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", "dev": true }, @@ -4790,25 +4790,25 @@ }, "lodash.mapvalues": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", + "resolved": "https://registry.npm.taobao.org/lodash.mapvalues/download/lodash.mapvalues-4.6.0.tgz", "integrity": "sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=", "dev": true }, "lodash.memoize": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "resolved": "https://registry.npm.taobao.org/lodash.memoize/download/lodash.memoize-4.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash.memoize%2Fdownload%2Flodash.memoize-4.1.2.tgz", "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, "lodash.transform": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.transform/-/lodash.transform-4.6.0.tgz", + "resolved": "https://registry.npm.taobao.org/lodash.transform/download/lodash.transform-4.6.0.tgz", "integrity": "sha1-EjBkIvYzJK7YSD0/ODMrX2cFR6A=", "dev": true }, "lodash.uniq": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "resolved": "https://registry.npm.taobao.org/lodash.uniq/download/lodash.uniq-4.5.0.tgz", "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", "dev": true }, @@ -4829,7 +4829,7 @@ }, "lower-case": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "resolved": "https://registry.npm.taobao.org/lower-case/download/lower-case-1.1.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flower-case%2Fdownload%2Flower-case-1.1.4.tgz", "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", "dev": true }, @@ -4862,13 +4862,13 @@ }, "map-cache": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "resolved": "https://registry.npm.taobao.org/map-cache/download/map-cache-0.2.2.tgz", "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, "map-visit": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/map-visit/download/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { @@ -4894,7 +4894,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "https://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, @@ -4919,7 +4919,7 @@ }, "memory-fs": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "resolved": "https://registry.npm.taobao.org/memory-fs/download/memory-fs-0.4.1.tgz?cache=0&sync_timestamp=1570537511500&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmemory-fs%2Fdownload%2Fmemory-fs-0.4.1.tgz", "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", "dev": true, "requires": { @@ -4929,7 +4929,7 @@ }, "merge-descriptors": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, @@ -4956,7 +4956,7 @@ }, "methods": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "resolved": "https://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", "dev": true }, @@ -5032,7 +5032,7 @@ "dependencies": { "normalize-url": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "resolved": "https://registry.npm.taobao.org/normalize-url/download/normalize-url-1.9.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnormalize-url%2Fdownload%2Fnormalize-url-1.9.1.tgz", "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", "dev": true, "requires": { @@ -5063,7 +5063,7 @@ }, "minimalistic-crypto-utils": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/minimalistic-crypto-utils/download/minimalistic-crypto-utils-1.0.1.tgz", "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", "dev": true }, @@ -5181,7 +5181,7 @@ }, "move-concurrently": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/move-concurrently/download/move-concurrently-1.0.1.tgz", "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", "dev": true, "requires": { @@ -5211,7 +5211,7 @@ }, "multicast-dns-service-types": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/multicast-dns-service-types/download/multicast-dns-service-types-1.1.0.tgz", "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", "dev": true }, @@ -5322,7 +5322,7 @@ "dependencies": { "punycode": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "resolved": "https://registry.npm.taobao.org/punycode/download/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true } @@ -5362,7 +5362,7 @@ }, "normalize-range": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "resolved": "https://registry.npm.taobao.org/normalize-range/download/normalize-range-0.1.2.tgz", "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", "dev": true }, @@ -5374,7 +5374,7 @@ }, "npm-run-path": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/npm-run-path/download/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { @@ -5392,13 +5392,13 @@ }, "num2fraction": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "resolved": "https://registry.npm.taobao.org/num2fraction/download/num2fraction-1.2.2.tgz", "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", "dev": true }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/number-is-nan/download/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, @@ -5410,13 +5410,13 @@ }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, "object-copy": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/object-copy/download/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { @@ -5427,7 +5427,7 @@ "dependencies": { "define-property": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { @@ -5436,7 +5436,7 @@ }, "kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz?cache=0&sync_timestamp=1579193926808&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fkind-of%2Fdownload%2Fkind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { @@ -5469,7 +5469,7 @@ }, "object-visit": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/object-visit/download/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { @@ -5500,7 +5500,7 @@ }, "object.pick": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "resolved": "https://registry.npm.taobao.org/object.pick/download/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { @@ -5527,7 +5527,7 @@ }, "on-finished": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "resolved": "https://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", "dev": true, "requires": { @@ -5551,7 +5551,7 @@ }, "onetime": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/onetime/download/onetime-2.0.1.tgz", "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { @@ -5624,7 +5624,7 @@ }, "os-browserify": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "resolved": "https://registry.npm.taobao.org/os-browserify/download/os-browserify-0.3.0.tgz", "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", "dev": true }, @@ -5641,13 +5641,13 @@ }, "p-defer": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/p-defer/download/p-defer-1.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fp-defer%2Fdownload%2Fp-defer-1.0.0.tgz", "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, "p-finally": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/p-finally/download/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, @@ -5718,7 +5718,7 @@ }, "param-case": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/param-case/download/param-case-2.1.1.tgz?cache=0&sync_timestamp=1576721509342&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fparam-case%2Fdownload%2Fparam-case-2.1.1.tgz", "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", "dev": true, "requires": { @@ -5774,7 +5774,7 @@ }, "pascalcase": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/pascalcase/download/pascalcase-0.1.1.tgz", "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true }, @@ -5786,7 +5786,7 @@ }, "path-dirname": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/path-dirname/download/path-dirname-1.0.2.tgz", "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", "dev": true }, @@ -5804,13 +5804,13 @@ }, "path-is-inside": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/path-is-inside/download/path-is-inside-1.0.2.tgz", "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, "path-key": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/path-key/download/path-key-2.0.1.tgz?cache=0&sync_timestamp=1574441404712&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpath-key%2Fdownload%2Fpath-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, @@ -5822,7 +5822,7 @@ }, "path-to-regexp": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "resolved": "https://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", "dev": true }, @@ -5837,7 +5837,7 @@ "dependencies": { "pify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/pify/download/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true } @@ -5858,7 +5858,7 @@ }, "performance-now": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/performance-now/download/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, @@ -5876,13 +5876,13 @@ }, "pinkie": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "resolved": "https://registry.npm.taobao.org/pinkie/download/pinkie-2.0.4.tgz", "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", "dev": true }, "pinkie-promise": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/pinkie-promise/download/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { @@ -5991,7 +5991,7 @@ }, "posix-character-classes": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/posix-character-classes/download/posix-character-classes-0.1.1.tgz", "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, @@ -6575,7 +6575,7 @@ }, "prepend-http": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "resolved": "https://registry.npm.taobao.org/prepend-http/download/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", "dev": true }, @@ -6588,7 +6588,7 @@ }, "pretty-error": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/pretty-error/download/pretty-error-2.1.1.tgz", "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", "dev": true, "requires": { @@ -6598,7 +6598,7 @@ }, "process": { "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "resolved": "https://registry.npm.taobao.org/process/download/process-0.11.10.tgz", "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", "dev": true }, @@ -6610,7 +6610,7 @@ }, "promise-inflight": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/promise-inflight/download/promise-inflight-1.0.1.tgz", "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, @@ -6626,13 +6626,13 @@ }, "prr": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/prr/download/prr-1.0.1.tgz", "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", "dev": true }, "pseudomap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, @@ -6697,7 +6697,7 @@ }, "q": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "resolved": "https://registry.npm.taobao.org/q/download/q-1.5.1.tgz", "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", "dev": true }, @@ -6709,7 +6709,7 @@ }, "query-string": { "version": "4.3.4", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "resolved": "https://registry.npm.taobao.org/query-string/download/query-string-4.3.4.tgz", "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", "dev": true, "requires": { @@ -6719,13 +6719,13 @@ }, "querystring": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "resolved": "https://registry.npm.taobao.org/querystring/download/querystring-0.2.0.tgz", "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", "dev": true }, "querystring-es3": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "resolved": "https://registry.npm.taobao.org/querystring-es3/download/querystring-es3-0.2.1.tgz", "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", "dev": true }, @@ -6847,13 +6847,13 @@ }, "relateurl": { "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "resolved": "https://registry.npm.taobao.org/relateurl/download/relateurl-0.2.7.tgz", "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", "dev": true }, "remove-trailing-separator": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/remove-trailing-separator/download/remove-trailing-separator-1.1.0.tgz", "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", "dev": true }, @@ -6872,13 +6872,13 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "css-select": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "resolved": "https://registry.npm.taobao.org/css-select/download/css-select-1.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcss-select%2Fdownload%2Fcss-select-1.2.0.tgz", "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "dev": true, "requires": { @@ -6896,7 +6896,7 @@ }, "domutils": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "resolved": "https://registry.npm.taobao.org/domutils/download/domutils-1.5.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomutils%2Fdownload%2Fdomutils-1.5.1.tgz", "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "dev": true, "requires": { @@ -6906,7 +6906,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1573280577145&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -6923,7 +6923,7 @@ }, "repeat-string": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "resolved": "https://registry.npm.taobao.org/repeat-string/download/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, @@ -6977,7 +6977,7 @@ }, "require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, @@ -6989,7 +6989,7 @@ }, "requires-port": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/requires-port/download/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, @@ -7004,7 +7004,7 @@ }, "resolve-cwd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/resolve-cwd/download/resolve-cwd-2.0.0.tgz", "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", "dev": true, "requires": { @@ -7013,19 +7013,19 @@ }, "resolve-from": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/resolve-from/download/resolve-from-3.0.0.tgz", "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", "dev": true }, "resolve-url": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "resolved": "https://registry.npm.taobao.org/resolve-url/download/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, "restore-cursor": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/restore-cursor/download/restore-cursor-2.0.0.tgz", "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { @@ -7041,19 +7041,19 @@ }, "retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "resolved": "https://registry.npm.taobao.org/retry/download/retry-0.12.0.tgz", "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", "dev": true }, "rgb-regex": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/rgb-regex/download/rgb-regex-1.0.1.tgz", "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", "dev": true }, "rgba-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/rgba-regex/download/rgba-regex-1.0.0.tgz", "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", "dev": true }, @@ -7078,7 +7078,7 @@ }, "run-queue": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "resolved": "https://registry.npm.taobao.org/run-queue/download/run-queue-1.0.3.tgz", "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", "dev": true, "requires": { @@ -7093,7 +7093,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/safe-regex/download/safe-regex-1.1.0.tgz?cache=0&sync_timestamp=1571687571136&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-regex%2Fdownload%2Fsafe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { @@ -7146,7 +7146,7 @@ }, "select-hose": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/select-hose/download/select-hose-2.0.0.tgz", "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", "dev": true }, @@ -7197,7 +7197,7 @@ "dependencies": { "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } @@ -7225,7 +7225,7 @@ }, "serve-index": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "resolved": "https://registry.npm.taobao.org/serve-index/download/serve-index-1.9.1.tgz", "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", "dev": true, "requires": { @@ -7249,7 +7249,7 @@ }, "http-errors": { "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { @@ -7261,13 +7261,13 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, @@ -7293,7 +7293,7 @@ }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/set-blocking/download/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, @@ -7311,7 +7311,7 @@ "dependencies": { "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { @@ -7322,7 +7322,7 @@ }, "setimmediate": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "resolved": "https://registry.npm.taobao.org/setimmediate/download/setimmediate-1.0.5.tgz", "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", "dev": true }, @@ -7353,7 +7353,7 @@ }, "shebang-command": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-1.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fshebang-command%2Fdownload%2Fshebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { @@ -7362,7 +7362,7 @@ }, "shebang-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, @@ -7391,7 +7391,7 @@ }, "simple-swizzle": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "resolved": "https://registry.npm.taobao.org/simple-swizzle/download/simple-swizzle-0.2.2.tgz", "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", "dev": true, "requires": { @@ -7408,7 +7408,7 @@ }, "slash": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/slash/download/slash-1.0.0.tgz", "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", "dev": true }, @@ -7439,7 +7439,7 @@ }, "define-property": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { @@ -7448,7 +7448,7 @@ }, "extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { @@ -7457,13 +7457,13 @@ }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true } @@ -7482,7 +7482,7 @@ "dependencies": { "define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { @@ -7531,7 +7531,7 @@ "dependencies": { "kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz?cache=0&sync_timestamp=1579193926808&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fkind-of%2Fdownload%2Fkind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { @@ -7586,7 +7586,7 @@ }, "sort-keys": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "resolved": "https://registry.npm.taobao.org/sort-keys/download/sort-keys-1.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsort-keys%2Fdownload%2Fsort-keys-1.1.2.tgz", "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", "dev": true, "requires": { @@ -7630,7 +7630,7 @@ }, "source-map-url": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "resolved": "https://registry.npm.taobao.org/source-map-url/download/source-map-url-0.4.0.tgz", "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, @@ -7717,7 +7717,7 @@ }, "sprintf-js": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "resolved": "https://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, @@ -7762,7 +7762,7 @@ }, "static-extend": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "resolved": "https://registry.npm.taobao.org/static-extend/download/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { @@ -7772,7 +7772,7 @@ "dependencies": { "define-property": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { @@ -7783,13 +7783,13 @@ }, "statuses": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "resolved": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, "stealthy-require": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/stealthy-require/download/stealthy-require-1.1.1.tgz", "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "dev": true }, @@ -7834,7 +7834,7 @@ }, "strict-uri-encode": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/strict-uri-encode/download/strict-uri-encode-1.1.0.tgz", "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "dev": true }, @@ -7850,13 +7850,13 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "strip-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz?cache=0&sync_timestamp=1573280577145&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { @@ -7943,7 +7943,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/strip-eof/download/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, @@ -8094,7 +8094,7 @@ }, "thenify": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", + "resolved": "https://registry.npm.taobao.org/thenify/download/thenify-3.3.0.tgz", "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", "dev": true, "requires": { @@ -8103,7 +8103,7 @@ }, "thenify-all": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "resolved": "https://registry.npm.taobao.org/thenify-all/download/thenify-all-1.6.0.tgz", "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", "dev": true, "requires": { @@ -8148,19 +8148,19 @@ }, "timsort": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "resolved": "https://registry.npm.taobao.org/timsort/download/timsort-0.3.0.tgz", "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", "dev": true }, "to-arraybuffer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/to-arraybuffer/download/to-arraybuffer-1.0.1.tgz", "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", "dev": true }, "to-object-path": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "resolved": "https://registry.npm.taobao.org/to-object-path/download/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { @@ -8169,7 +8169,7 @@ "dependencies": { "kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz?cache=0&sync_timestamp=1579193926808&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fkind-of%2Fdownload%2Fkind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { @@ -8192,7 +8192,7 @@ }, "to-regex-range": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-2.1.1.tgz", "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { @@ -8208,7 +8208,7 @@ }, "toposort": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "resolved": "https://registry.npm.taobao.org/toposort/download/toposort-1.0.7.tgz", "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", "dev": true }, @@ -8242,13 +8242,13 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/tty-browserify/download/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, "tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "resolved": "https://registry.npm.taobao.org/tunnel-agent/download/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { @@ -8257,7 +8257,7 @@ }, "tweetnacl": { "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "resolved": "https://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, @@ -8279,7 +8279,7 @@ }, "typedarray": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "resolved": "https://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, @@ -8315,13 +8315,13 @@ }, "uniq": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/uniq/download/uniq-1.0.1.tgz", "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", "dev": true }, "uniqs": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/uniqs/download/uniqs-2.0.0.tgz", "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", "dev": true }, @@ -8351,19 +8351,19 @@ }, "unpipe": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, "unquote": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/unquote/download/unquote-1.1.1.tgz", "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", "dev": true }, "unset-value": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/unset-value/download/unset-value-1.0.0.tgz", "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { @@ -8373,7 +8373,7 @@ "dependencies": { "has-value": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "resolved": "https://registry.npm.taobao.org/has-value/download/has-value-0.3.1.tgz", "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { @@ -8384,7 +8384,7 @@ "dependencies": { "isobject": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/isobject/download/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", "dev": true, "requires": { @@ -8395,7 +8395,7 @@ }, "has-values": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "resolved": "https://registry.npm.taobao.org/has-values/download/has-values-0.1.4.tgz", "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", "dev": true } @@ -8409,7 +8409,7 @@ }, "upper-case": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "resolved": "https://registry.npm.taobao.org/upper-case/download/upper-case-1.1.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fupper-case%2Fdownload%2Fupper-case-1.1.3.tgz", "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", "dev": true }, @@ -8424,13 +8424,13 @@ }, "urix": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/urix/download/urix-0.1.0.tgz", "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, "url": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "resolved": "https://registry.npm.taobao.org/url/download/url-0.11.0.tgz", "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", "dev": true, "requires": { @@ -8440,7 +8440,7 @@ "dependencies": { "punycode": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "resolved": "https://registry.npm.taobao.org/punycode/download/punycode-1.3.2.tgz", "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", "dev": true } @@ -8484,7 +8484,7 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true } @@ -8492,7 +8492,7 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, @@ -8510,13 +8510,13 @@ }, "utila": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "resolved": "https://registry.npm.taobao.org/utila/download/utila-0.4.0.tgz", "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", "dev": true }, "utils-merge": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", "dev": true }, @@ -8538,7 +8538,7 @@ }, "vary": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "resolved": "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "dev": true }, @@ -8550,7 +8550,7 @@ }, "verror": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "resolved": "https://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { @@ -8570,6 +8570,11 @@ "resolved": "https://registry.npm.taobao.org/vue/download/vue-2.6.11.tgz", "integrity": "sha1-dllNh31LEiNEBuhONSdcbVFBJcU=" }, + "vue-axios": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/vue-axios/-/vue-axios-2.1.5.tgz", + "integrity": "sha512-th5xVbInVoyIoe+qY+9GCflEVezxAvztD4xpFF39SRQYqpoKD2qkmX8yv08jJG9a2SgNOCjirjJGSwg/wTrbmA==" + }, "vue-cli-plugin-vuetify": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/vue-cli-plugin-vuetify/-/vue-cli-plugin-vuetify-2.0.5.tgz", @@ -8676,6 +8681,11 @@ "loader-utils": "^1.2.0" } }, + "vuex": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.2.0.tgz", + "integrity": "sha512-qBZGJJ1gUNWZbfZlH7ylIPwENg3R0Ckpq+qPexF065kOMOt1Ixt8WDJmtssVv7OhepWD0+Qie7pOS8f0oQy1JA==" + }, "watchpack": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.1.tgz", @@ -9316,7 +9326,7 @@ }, "wcwidth": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/wcwidth/download/wcwidth-1.0.1.tgz", "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", "dev": true, "requires": { @@ -9564,7 +9574,7 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, @@ -9628,13 +9638,13 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "strip-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz?cache=0&sync_timestamp=1573280577145&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { @@ -10224,7 +10234,7 @@ }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { @@ -10278,7 +10288,7 @@ }, "require-main-filename": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/require-main-filename/download/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, @@ -10295,7 +10305,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1573280577145&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -10313,7 +10323,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -10323,7 +10333,7 @@ "dependencies": { "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -10423,7 +10433,7 @@ }, "which-module": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, diff --git a/ui/package.json b/ui/package.json index 4f0b8dd..19a032c 100644 --- a/ui/package.json +++ b/ui/package.json @@ -11,9 +11,11 @@ "is-cidr": "^3.1.0", "moment": "^2.24.0", "vue": "^2.6.10", + "vue-axios": "^2.1.5", "vue-moment": "^4.1.0", "vue-router": "^3.1.6", - "vuetify": "^2.2.22" + "vuetify": "^2.2.22", + "vuex": "^3.2.0" }, "devDependencies": { "@vue/cli-plugin-router": "^4.3.1", diff --git a/ui/src/App.vue b/ui/src/App.vue index 519cf15..32c317f 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -1,69 +1,36 @@ diff --git a/ui/src/components/Footer.vue b/ui/src/components/Footer.vue new file mode 100644 index 0000000..336f8a8 --- /dev/null +++ b/ui/src/components/Footer.vue @@ -0,0 +1,51 @@ + + + diff --git a/ui/src/components/Header.vue b/ui/src/components/Header.vue new file mode 100644 index 0000000..58ca18f --- /dev/null +++ b/ui/src/components/Header.vue @@ -0,0 +1,77 @@ + + + diff --git a/ui/src/components/Server.vue b/ui/src/components/Server.vue index c8fdffc..5a70e94 100644 --- a/ui/src/components/Server.vue +++ b/ui/src/components/Server.vue @@ -158,7 +158,7 @@ Download server configuration mdi-cloud-download-outline @@ -167,52 +167,44 @@ Update server configuration mdi-update - diff --git a/ui/src/main.js b/ui/src/main.js index bfb2c50..fea553f 100644 --- a/ui/src/main.js +++ b/ui/src/main.js @@ -1,14 +1,18 @@ import Vue from 'vue' import App from './App.vue' import router from './router' +import store from './store' import vuetify from './plugins/vuetify'; import './plugins/moment'; import './plugins/cidr' +import './plugins/axios' -Vue.config.productionTip = false +// Don't warn about using the dev version of Vue in development. +Vue.config.productionTip = process.env.NODE_ENV === 'production' new Vue({ router, + store, vuetify, render: function (h) { return h(App) } }).$mount('#app') diff --git a/ui/src/plugins/axios.js b/ui/src/plugins/axios.js new file mode 100644 index 0000000..444ef90 --- /dev/null +++ b/ui/src/plugins/axios.js @@ -0,0 +1,26 @@ +import Vue from 'vue' +import axios from "axios"; +import VueAxios from "vue-axios"; +import TokenService from "../services/token.service"; + +Vue.use(VueAxios, axios); + +let baseUrl = "/api/v1.0"; +if (process.env.NODE_ENV === "development"){ + baseUrl = process.env.VUE_APP_API_BASE_URL; +} + +Vue.axios.defaults.baseURL = baseUrl; + +Vue.axios.interceptors.response.use(function (response) { + return response; +}, function (error) { + if (401 === error.response.status) { + TokenService.destroyToken(); + TokenService.destroyClientId(); + window.location = '/'; + } else { + return Promise.reject(error); + } +}); + diff --git a/ui/src/router/index.js b/ui/src/router/index.js index bbd46bb..ee29359 100644 --- a/ui/src/router/index.js +++ b/ui/src/router/index.js @@ -1,22 +1,19 @@ import Vue from 'vue' import VueRouter from 'vue-router' +import store from "../store"; Vue.use(VueRouter); const routes = [ - { - path: '/', - name: 'index', - component: function () { - return import(/* webpackChunkName: "Index" */ '../views/Index.vue') - }, - }, { path: '/clients', name: 'clients', component: function () { return import(/* webpackChunkName: "Clients" */ '../views/Clients.vue') }, + meta: { + requiresAuth: true + } }, { path: '/server', @@ -24,6 +21,9 @@ const routes = [ component: function () { return import(/* webpackChunkName: "Server" */ '../views/Server.vue') }, + meta: { + requiresAuth: true + } } ]; @@ -33,4 +33,16 @@ const router = new VueRouter({ routes }); +router.beforeEach((to, from, next) => { + if(to.matched.some(record => record.meta.requiresAuth)) { + if (store.getters["auth/isAuthenticated"]) { + next() + return + } + next('/') + } else { + next() + } +}) + export default router diff --git a/ui/src/services/ApiService.js b/ui/src/services/ApiService.js deleted file mode 100644 index dc55572..0000000 --- a/ui/src/services/ApiService.js +++ /dev/null @@ -1,40 +0,0 @@ -import axios from 'axios' - -let baseUrl = "/api/v1.0"; -if (process.env.NODE_ENV === "development"){ - baseUrl = process.env.VUE_APP_API_BASE_URL -} - -export const API_BASE_URL = baseUrl; - -export class ApiService { - get(resource) { - return axios - .get(`${API_BASE_URL}${resource}`) - .then(response => response.data) - }; - - post(resource, data) { - return axios - .post(`${API_BASE_URL}${resource}`, data) - .then(response => response.data) - }; - - put(resource, data) { - return axios - .put(`${API_BASE_URL}${resource}`, data) - .then(response => response.data) - }; - - patch(resource, data) { - return axios - .patch(`${API_BASE_URL}${resource}`, data) - .then(response => response.data) - }; - - delete(resource) { - return axios - .delete(`${API_BASE_URL}${resource}`) - .then(response => response.data) - }; -} diff --git a/ui/src/services/api.service.js b/ui/src/services/api.service.js new file mode 100644 index 0000000..97b0093 --- /dev/null +++ b/ui/src/services/api.service.js @@ -0,0 +1,59 @@ +import Vue from "vue"; +import TokenService from "./token.service"; + +const ApiService = { + + setHeader() { + Vue.axios.defaults.headers.common.Authorization = `${TokenService.getToken()}`; + }, + + get(resource) { + return Vue.axios.get(resource) + .then(response => response.data) + .catch(error => { + throw new Error(`ApiService: ${error}`) + }); + }, + + post(resource, params) { + return Vue.axios.post(resource, params) + .then(response => response.data) + .catch(error => { + throw new Error(`ApiService: ${error}`) + }); + }, + + put(resource, params) { + return Vue.axios.put(resource, params) + .then(response => response.data) + .catch(error => { + throw new Error(`ApiService: ${error}`) + }); + }, + + patch(resource, params) { + return Vue.axios.patch(resource, params) + .then(response => response.data) + .catch(error => { + throw new Error(`ApiService: ${error}`) + }); + }, + + delete(resource) { + return Vue.axios.delete(resource) + .then(response => response.data) + .catch(error => { + throw new Error(`ApiService: ${error}`) + }); + }, + + getWithConfig(resource, config) { + return Vue.axios.get(resource, config) + .then(response => response.data) + .catch(error => { + throw new Error(`ApiService: ${error}`) + }); + }, +}; + +export default ApiService; diff --git a/ui/src/services/token.service.js b/ui/src/services/token.service.js new file mode 100644 index 0000000..cbbb12d --- /dev/null +++ b/ui/src/services/token.service.js @@ -0,0 +1,35 @@ +const TOKEN_KEY = "token"; +const CLIENT_ID_KEY = "client_id"; + +export const getToken = () => { + return window.localStorage.getItem(TOKEN_KEY); +}; + +export const saveToken = token => { + window.localStorage.setItem(TOKEN_KEY, token); +}; + +export const destroyToken = () => { + window.localStorage.removeItem(TOKEN_KEY); +}; + +export const getClientId = () => { + return window.localStorage.getItem(CLIENT_ID_KEY); +}; + +export const saveClientId = token => { + window.localStorage.setItem(CLIENT_ID_KEY, token); +}; + +export const destroyClientId = () => { + window.localStorage.removeItem(CLIENT_ID_KEY); +}; + +export default { + getToken, + saveToken, + destroyToken, + getClientId, + saveClientId, + destroyClientId +}; diff --git a/ui/src/store/index.js b/ui/src/store/index.js new file mode 100644 index 0000000..97b5b76 --- /dev/null +++ b/ui/src/store/index.js @@ -0,0 +1,19 @@ +import Vue from 'vue' +import Vuex from 'vuex' +import auth from "./modules/auth"; +import client from "./modules/client"; +import server from "./modules/server"; + +Vue.use(Vuex) + +export default new Vuex.Store({ + state: {}, + getters : {}, + mutations: {}, + actions:{}, + modules: { + auth, + client, + server + } +}) diff --git a/ui/src/store/modules/auth.js b/ui/src/store/modules/auth.js new file mode 100644 index 0000000..90b7e07 --- /dev/null +++ b/ui/src/store/modules/auth.js @@ -0,0 +1,126 @@ +import ApiService from "../../services/api.service"; +import TokenService from "../../services/token.service"; + +const state = { + error: null, + user: null, + authStatus: '', + authRedirectUrl: '', +}; + +const getters = { + error(state) { + return state.error; + }, + user(state) { + return state.user; + }, + isAuthenticated(state) { + return state.user !== null; + }, + authRedirectUrl(state) { + return state.authRedirectUrl + }, + authStatus(state) { + return state.authStatus + }, +}; + +const actions = { + user({ commit }){ + ApiService.get("/auth/user") + .then( resp => { + commit('user', resp) + }) + .catch(err => { + commit('error', err); + commit('logout') + }); + }, + + oauth2_url({ commit, dispatch }){ + if (TokenService.getToken()) { + ApiService.setHeader(); + dispatch('user'); + return + } + ApiService.get("/auth/oauth2_url") + .then(resp => { + if (resp.codeUrl === '_magic_string_fake_auth_no_redirect_'){ + console.log("server report oauth2 is disabled, fake exchange") + commit('authStatus', 'disabled') + TokenService.saveClientId(resp.clientId) + dispatch('oauth2_exchange', {code: "", state: resp.state}) + } else { + commit('authStatus', 'redirect') + commit('authRedirectUrl', resp) + } + }) + .catch(err => { + commit('authStatus', 'error') + commit('error', err); + commit('logout') + }) + }, + + oauth2_exchange({ commit, dispatch }, data){ + data.clientId = TokenService.getClientId() + ApiService.post("/auth/oauth2_exchange", data) + .then(resp => { + commit('authStatus', 'success') + commit('token', resp) + dispatch('user'); + }) + .catch(err => { + commit('authStatus', 'error') + commit('error', err); + commit('logout') + }) + }, + + logout({ commit }){ + ApiService.get("/auth/logout") + .then(resp => { + commit('logout') + }) + .catch(err => { + commit('authStatus', '') + commit('error', err); + commit('logout') + }) + }, +} + +const mutations = { + error(state, error) { + state.error = error; + }, + authStatus(state, authStatus) { + state.authStatus = authStatus; + }, + authRedirectUrl(state, resp) { + state.authRedirectUrl = resp.codeUrl; + TokenService.saveClientId(resp.clientId); + }, + token(state, token) { + TokenService.saveToken(token); + ApiService.setHeader(); + TokenService.destroyClientId(); + }, + user(state, user) { + state.user = user; + }, + logout(state) { + state.user = null; + TokenService.destroyToken(); + TokenService.destroyClientId(); + } +}; + +export default { + namespaced: true, + state, + getters, + actions, + mutations +} diff --git a/ui/src/store/modules/client.js b/ui/src/store/modules/client.js new file mode 100644 index 0000000..8453b35 --- /dev/null +++ b/ui/src/store/modules/client.js @@ -0,0 +1,177 @@ +import ApiService from "../../services/api.service"; + +const state = { + error: null, + clients: [], + clientQrcodes: [], + clientConfigs: [] +} + +const getters = { + error(state) { + return state.error; + }, + clients(state) { + return state.clients; + }, + getClientQrcode: (state) => (id) => { + let item = state.clientQrcodes.find(item => item.id === id) + // initial load fails, must wait promise and stuff... + return item ? item.qrcode : "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==" + }, + getClientConfig: (state) => (id) => { + let item = state.clientConfigs.find(item => item.id === id) + return item ? item.config : null + } +} + +const actions = { + error({ commit }, error){ + commit('error', error) + }, + + readAll({ commit, dispatch }){ + ApiService.get("/client") + .then(resp => { + commit('clients', resp) + dispatch('readQrcodes') + dispatch('readConfigs') + }) + .catch(err => { + commit('error', err) + }) + }, + + create({ commit, dispatch }, client){ + ApiService.post("/client", client) + .then(resp => { + dispatch('readQrcode', resp) + dispatch('readConfig', resp) + commit('create', resp) + }) + .catch(err => { + commit('error', err) + }) + }, + + update({ commit, dispatch }, client){ + ApiService.patch(`/client/${client.id}`, client) + .then(resp => { + dispatch('readQrcode', resp) + dispatch('readConfig', resp) + commit('update', resp) + }) + .catch(err => { + commit('error', err) + }) + }, + + delete({ commit }, client){ + ApiService.delete(`/client/${client.id}`) + .then(() => { + commit('delete', client) + }) + .catch(err => { + commit('error', err) + }) + }, + + email({ commit }, client){ + ApiService.get(`/client/${client.id}/email`) + .then(() => { + }) + .catch(err => { + commit('error', err) + }) + }, + + readQrcode({ state, commit }, client){ + ApiService.getWithConfig(`/client/${client.id}/config?qrcode=true`, {responseType: 'arraybuffer'}) + .then(resp => { + let image = Buffer.from(resp, 'binary').toString('base64') + commit('clientQrcodes', { client, image }) + }) + .catch(err => { + commit('error', err) + }) + }, + + readConfig({ state, commit }, client){ + ApiService.getWithConfig(`/client/${client.id}/config?qrcode=false`, {responseType: 'arraybuffer'}) + .then(resp => { + commit('clientConfigs', { client: client, config: resp }) + }) + .catch(err => { + commit('error', err) + }) + }, + + readQrcodes({ state, dispatch }){ + state.clients.forEach(client => { + dispatch('readQrcode', client) + }) + }, + + readConfigs({ state, dispatch }){ + state.clients.forEach(client => { + dispatch('readConfig', client) + }) + }, +} + +const mutations = { + error(state, error) { + state.error = error; + }, + clients(state, clients){ + state.clients = clients + }, + create(state, client){ + state.clients.push(client) + }, + update(state, client){ + let index = state.clients.findIndex(x => x.id === client.id); + if (index !== -1) { + state.clients.splice(index, 1); + state.clients.push(client); + } else { + state.error = "update client failed, not in list" + } + }, + delete(state, client){ + let index = state.clients.findIndex(x => x.id === client.id); + if (index !== -1) { + state.clients.splice(index, 1); + } else { + state.error = "delete client failed, not in list" + } + }, + clientQrcodes(state, { client, image }){ + let index = state.clientQrcodes.findIndex(x => x.id === client.id); + if (index !== -1) { + state.clientQrcodes.splice(index, 1); + } + state.clientQrcodes.push({ + id: client.id, + qrcode: image + }) + }, + clientConfigs(state, { client, config }){ + let index = state.clientConfigs.findIndex(x => x.id === client.id); + if (index !== -1) { + state.clientConfigs.splice(index, 1); + } + state.clientConfigs.push({ + id: client.id, + config: config + }) + }, +} + +export default { + namespaced: true, + state, + getters, + actions, + mutations +} diff --git a/ui/src/store/modules/server.js b/ui/src/store/modules/server.js new file mode 100644 index 0000000..63ba169 --- /dev/null +++ b/ui/src/store/modules/server.js @@ -0,0 +1,100 @@ +import ApiService from "../../services/api.service"; + +const state = { + error: null, + server: null, + config: '', + version: '_ci_build_not_run_properly_', +} + +const getters = { + error(state) { + return state.error; + }, + + server(state) { + return state.server; + }, + + version(state) { + return state.version; + }, + + config(state) { + return state.config; + }, +} + +const actions = { + error({ commit }, error){ + commit('error', error) + }, + + read({ commit, dispatch }){ + ApiService.get("/server") + .then(resp => { + commit('server', resp) + dispatch('config') + }) + .catch(err => { + commit('error', err) + }) + }, + + update({ commit }, server){ + ApiService.patch(`/server`, server) + .then(resp => { + commit('server', resp) + }) + .catch(err => { + commit('error', err) + }) + }, + + config({ commit }){ + ApiService.getWithConfig("/server/config", {responseType: 'arraybuffer'}) + .then(resp => { + commit('config', resp) + }) + .catch(err => { + commit('error', err) + }) + }, + + version({ commit }){ + ApiService.get("/server/version") + .then(resp => { + commit('version', resp.version) + }) + .catch(err => { + commit('error', err) + }) + }, + +} + +const mutations = { + error(state, error) { + state.error = error; + }, + + server(state, server){ + state.server = server + }, + + config(state, config){ + state.config = config + }, + + version(state, version){ + state.version = version + }, +} + +export default { + namespaced: true, + state, + getters, + actions, + mutations +} diff --git a/ui/src/views/Index.vue b/ui/src/views/Index.vue deleted file mode 100644 index 46ed1f1..0000000 --- a/ui/src/views/Index.vue +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/util/util.go b/util/util.go index 5d7e323..3d3f88c 100644 --- a/util/util.go +++ b/util/util.go @@ -1,6 +1,8 @@ package util import ( + "crypto/rand" + "encoding/base64" "errors" "io/ioutil" "net" @@ -9,6 +11,7 @@ import ( ) var ( + AuthTokenHeaderName = "Authorization" // RegexpEmail check valid email RegexpEmail = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$") ) @@ -51,7 +54,7 @@ func DirectoryExists(name string) bool { return info.IsDir() } -// GetAvailableIp search for an available in cidr against a list of reserved ips +// GetAvailableIp search for an available ip in cidr against a list of reserved ips func GetAvailableIp(cidr string, reserved []string) (string, error) { ip, ipnet, err := net.ParseCIDR(cidr) if err != nil { @@ -132,3 +135,28 @@ func BroadcastAddr(n *net.IPNet) net.IP { } return broadcast } + +// GenerateRandomBytes returns securely generated random bytes. +// It will return an error if the system's secure random +// number generator fails to function correctly, in which +// case the caller should not continue. +func GenerateRandomBytes(n int) ([]byte, error) { + b := make([]byte, n) + _, err := rand.Read(b) + // Note that err == nil only if we read len(b) bytes. + if err != nil { + return nil, err + } + + return b, nil +} + +// GenerateRandomString returns a URL-safe, base64 encoded +// securely generated random string. +// It will return an error if the system's secure random +// number generator fails to function correctly, in which +// case the caller should not continue. +func GenerateRandomString(s int) (string, error) { + b, err := GenerateRandomBytes(s) + return base64.URLEncoding.EncodeToString(b), err +}