github.com/elliott5/community@v0.14.1-0.20160709191136-823126fb026a/documize/api/endpoint/router.go (about) 1 // Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved. 2 // 3 // This software (Documize Community Edition) is licensed under 4 // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html 5 // 6 // You can operate outside the AGPL restrictions by purchasing 7 // Documize Enterprise Edition and obtaining a commercial license 8 // by contacting <sales@documize.com>. 9 // 10 // https://documize.com 11 12 package endpoint 13 14 import ( 15 "fmt" 16 "net/http" 17 "os" 18 "strings" 19 20 "github.com/codegangsta/negroni" 21 "github.com/documize/community/documize/api/plugins" 22 "github.com/documize/community/documize/database" 23 "github.com/documize/community/documize/web" 24 "github.com/documize/community/wordsmith/environment" 25 "github.com/documize/community/wordsmith/log" 26 "github.com/gorilla/mux" 27 ) 28 29 const ( 30 // AppVersion does what it says 31 // Note: versioning scheme is not http://semver.org 32 AppVersion = "0.14.0" 33 ) 34 35 var port, certFile, keyFile, forcePort2SSL string 36 37 func init() { 38 environment.GetString(&certFile, "cert", false, "the cert.pem file used for https", nil) 39 environment.GetString(&keyFile, "key", false, "the key.pem file used for https", nil) 40 environment.GetString(&port, "port", false, "http/https port number", nil) 41 environment.GetString(&forcePort2SSL, "forcesslport", false, "redirect given http port number to TLS", nil) 42 } 43 44 var testHost string // used during automated testing 45 46 // Serve the Documize endpoint. 47 func Serve(ready chan struct{}) { 48 err := plugins.LibSetup() 49 50 if err != nil { 51 log.Error("Terminating before running - invalid plugin.json", err) 52 os.Exit(1) 53 } 54 55 log.Info(fmt.Sprintf("Documize version %s", AppVersion)) 56 57 router := mux.NewRouter() 58 59 router.PathPrefix("/api/public/").Handler(negroni.New( 60 negroni.HandlerFunc(cors), 61 negroni.Wrap(buildUnsecureRoutes()), 62 )) 63 64 router.PathPrefix("/api").Handler(negroni.New( 65 negroni.HandlerFunc(Authorize), 66 negroni.Wrap(buildSecureRoutes()), 67 )) 68 69 router.PathPrefix("/").Handler(negroni.New( 70 negroni.HandlerFunc(cors), 71 negroni.Wrap(AppRouter()), 72 )) 73 74 n := negroni.New() 75 n.Use(negroni.NewStatic(web.StaticAssetsFileSystem())) 76 n.Use(negroni.HandlerFunc(cors)) 77 n.Use(negroni.HandlerFunc(metrics)) 78 n.UseHandler(router) 79 ready <- struct{}{} 80 81 if certFile == "" && keyFile == "" { 82 if port == "" { 83 port = "80" 84 } 85 86 log.Info("Starting non-SSL server on " + port) 87 88 n.Run(testHost + ":" + port) 89 } else { 90 if port == "" { 91 port = "443" 92 } 93 94 if forcePort2SSL != "" { 95 log.Info("Starting non-SSL server on " + forcePort2SSL + " and redirecting to SSL server on " + port) 96 97 go func() { 98 err := http.ListenAndServe(":"+forcePort2SSL, http.HandlerFunc( 99 func(w http.ResponseWriter, req *http.Request) { 100 var host = strings.Replace(req.Host, forcePort2SSL, port, 1) + req.RequestURI 101 http.Redirect(w, req, "https://"+host, http.StatusMovedPermanently) 102 })) 103 if err != nil { 104 log.Error("ListenAndServe on "+forcePort2SSL, err) 105 } 106 }() 107 } 108 109 log.Info("Starting SSL server on " + port + " with " + certFile + " " + keyFile) 110 111 server := &http.Server{Addr: ":" + port, Handler: n} 112 server.SetKeepAlivesEnabled(true) 113 if err := server.ListenAndServeTLS(certFile, keyFile); err != nil { 114 log.Error("ListenAndServeTLS on "+port, err) 115 } 116 } 117 } 118 119 func buildUnsecureRoutes() *mux.Router { 120 router := mux.NewRouter() 121 122 router.HandleFunc("/api/public/meta", GetMeta).Methods("GET", "OPTIONS") 123 router.HandleFunc("/api/public/authenticate", Authenticate).Methods("POST", "OPTIONS") 124 router.HandleFunc("/api/public/validate", ValidateAuthToken).Methods("GET", "OPTIONS") 125 router.HandleFunc("/api/public/forgot", ForgotUserPassword).Methods("POST", "OPTIONS") 126 router.HandleFunc("/api/public/reset/{token}", ResetUserPassword).Methods("POST", "OPTIONS") 127 router.HandleFunc("/api/public/share/{folderID}", AcceptSharedFolder).Methods("POST", "OPTIONS") 128 router.HandleFunc("/api/public/attachments/{orgID}/{job}/{fileID}", AttachmentDownload).Methods("GET", "OPTIONS") 129 router.HandleFunc("/api/public/version", version).Methods("GET", "OPTIONS") 130 131 return router 132 } 133 134 func buildSecureRoutes() *mux.Router { 135 router := mux.NewRouter() 136 137 // Import & Convert Document 138 router.HandleFunc("/api/import/folder/{folderID}", UploadConvertDocument).Methods("POST", "OPTIONS") 139 140 // Document 141 router.HandleFunc("/api/documents/{documentID}/export", GetDocumentAsDocx).Methods("GET", "OPTIONS") 142 router.HandleFunc("/api/documents", GetDocumentsByTag).Methods("GET", "OPTIONS").Queries("filter", "tag") 143 router.HandleFunc("/api/documents", GetDocumentsByFolder).Methods("GET", "OPTIONS") 144 router.HandleFunc("/api/documents/{documentID}", GetDocument).Methods("GET", "OPTIONS") 145 router.HandleFunc("/api/documents/{documentID}", UpdateDocument).Methods("PUT", "OPTIONS") 146 router.HandleFunc("/api/documents/{documentID}", DeleteDocument).Methods("DELETE", "OPTIONS") 147 148 // Document Meta 149 router.HandleFunc("/api/documents/{documentID}/meta", GetDocumentMeta).Methods("GET", "OPTIONS") 150 151 // Document Page 152 router.HandleFunc("/api/documents/{documentID}/pages/level", ChangeDocumentPageLevel).Methods("POST", "OPTIONS") 153 router.HandleFunc("/api/documents/{documentID}/pages/sequence", ChangeDocumentPageSequence).Methods("POST", "OPTIONS") 154 router.HandleFunc("/api/documents/{documentID}/pages/batch", GetDocumentPagesBatch).Methods("POST", "OPTIONS") 155 // router.HandleFunc("/api/documents/{documentID}/pages/{pageID}/revisions", GetDocumentPageRevisions).Methods("GET", "OPTIONS") 156 // router.HandleFunc("/api/documents/{documentID}/pages/{pageID}/revisions/{revisionID}", GetDocumentPageDiff).Methods("GET", "OPTIONS") 157 // router.HandleFunc("/api/documents/{documentID}/pages/{pageID}/revisions/{revisionID}", RollbackDocumentPage).Methods("POST", "OPTIONS") 158 router.HandleFunc("/api/documents/{documentID}/pages", GetDocumentPages).Methods("GET", "OPTIONS") 159 router.HandleFunc("/api/documents/{documentID}/pages/{pageID}", UpdateDocumentPage).Methods("PUT", "OPTIONS") 160 router.HandleFunc("/api/documents/{documentID}/pages/{pageID}", DeleteDocumentPage).Methods("DELETE", "OPTIONS") 161 router.HandleFunc("/api/documents/{documentID}/pages/{pageID}", DeleteDocumentPages).Methods("POST", "OPTIONS") 162 router.HandleFunc("/api/documents/{documentID}/pages/{pageID}", GetDocumentPage).Methods("GET", "OPTIONS") 163 router.HandleFunc("/api/documents/{documentID}/pages", AddDocumentPage).Methods("POST", "OPTIONS") 164 router.HandleFunc("/api/documents/{documentID}/attachments", GetAttachments).Methods("GET", "OPTIONS") 165 router.HandleFunc("/api/documents/{documentID}/attachments/{attachmentID}", DeleteAttachment).Methods("DELETE", "OPTIONS") 166 router.HandleFunc("/api/documents/{documentID}/attachments", AddAttachments).Methods("POST", "OPTIONS") 167 168 // Document Meta 169 router.HandleFunc("/api/documents/{documentID}/pages/{pageID}/meta", GetDocumentPageMeta).Methods("GET", "OPTIONS") 170 171 // Organization 172 router.HandleFunc("/api/organizations/{orgID}", GetOrganization).Methods("GET", "OPTIONS") 173 router.HandleFunc("/api/organizations/{orgID}", UpdateOrganization).Methods("PUT", "OPTIONS") 174 175 // Folder 176 router.HandleFunc("/api/folders/{folderID}/move/{moveToId}", RemoveFolder).Methods("DELETE", "OPTIONS") 177 router.HandleFunc("/api/folders/{folderID}/permissions", SetFolderPermissions).Methods("PUT", "OPTIONS") 178 router.HandleFunc("/api/folders/{folderID}/permissions", GetFolderPermissions).Methods("GET", "OPTIONS") 179 router.HandleFunc("/api/folders/{folderID}/invitation", InviteToFolder).Methods("POST", "OPTIONS") 180 router.HandleFunc("/api/folders", GetFolderVisibility).Methods("GET", "OPTIONS").Queries("filter", "viewers") 181 router.HandleFunc("/api/folders", AddFolder).Methods("POST", "OPTIONS") 182 router.HandleFunc("/api/folders", GetFolders).Methods("GET", "OPTIONS") 183 router.HandleFunc("/api/folders/{folderID}", GetFolder).Methods("GET", "OPTIONS") 184 router.HandleFunc("/api/folders/{folderID}", UpdateFolder).Methods("PUT", "OPTIONS") 185 186 // Users 187 router.HandleFunc("/api/users/{userID}/password", ChangeUserPassword).Methods("POST", "OPTIONS") 188 router.HandleFunc("/api/users/{userID}/permissions", GetUserFolderPermissions).Methods("GET", "OPTIONS") 189 router.HandleFunc("/api/users", AddUser).Methods("POST", "OPTIONS") 190 router.HandleFunc("/api/users/folder/{folderID}", GetFolderUsers).Methods("GET", "OPTIONS") 191 router.HandleFunc("/api/users", GetOrganizationUsers).Methods("GET", "OPTIONS") 192 router.HandleFunc("/api/users/{userID}", GetUser).Methods("GET", "OPTIONS") 193 router.HandleFunc("/api/users/{userID}", UpdateUser).Methods("PUT", "OPTIONS") 194 router.HandleFunc("/api/users/{userID}", DeleteUser).Methods("DELETE", "OPTIONS") 195 196 // Search 197 router.HandleFunc("/api/search", SearchDocuments).Methods("GET", "OPTIONS") 198 199 // Templates 200 router.HandleFunc("/api/templates", SaveAsTemplate).Methods("POST", "OPTIONS") 201 router.HandleFunc("/api/templates", GetSavedTemplates).Methods("GET", "OPTIONS") 202 router.HandleFunc("/api/templates/stock", GetStockTemplates).Methods("GET", "OPTIONS") 203 router.HandleFunc("/api/templates/{templateID}/folder/{folderID}", StartDocumentFromStockTemplate).Methods("POST", "OPTIONS").Queries("type", "stock") 204 router.HandleFunc("/api/templates/{templateID}/folder/{folderID}", StartDocumentFromSavedTemplate).Methods("POST", "OPTIONS").Queries("type", "saved") 205 206 // Sections 207 router.HandleFunc("/api/sections", GetSections).Methods("GET", "OPTIONS") 208 router.HandleFunc("/api/sections", RunSectionCommand).Methods("POST", "OPTIONS") 209 router.HandleFunc("/api/sections/refresh", RefreshSections).Methods("GET", "OPTIONS") 210 211 return router 212 } 213 214 func cors(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 215 w.Header().Set("Access-Control-Allow-Origin", "*") 216 w.Header().Set("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS, PATCH") 217 w.Header().Set("Access-Control-Allow-Headers", "host, content-type, accept, authorization, origin, referer, user-agent, cache-control, x-requested-with") 218 w.Header().Set("Access-Control-Expose-Headers", "x-documize-version") 219 220 if r.Method == "OPTIONS" { 221 if _, err := w.Write([]byte("")); err != nil { 222 log.Error("cors", err) 223 } 224 return 225 } 226 227 next(w, r) 228 } 229 230 func metrics(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 231 w.Header().Add("X-Documize-Version", AppVersion) 232 w.Header().Add("Cache-Control", "no-cache") 233 234 // if certFile != "" && keyFile != "" { 235 // w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains") 236 // } 237 238 next(w, r) 239 } 240 241 func version(w http.ResponseWriter, r *http.Request) { 242 if _, err := w.Write([]byte(AppVersion)); err != nil { 243 log.Error("versionHandler", err) 244 } 245 } 246 247 // AppRouter configures single page app handler. 248 func AppRouter() *mux.Router { 249 250 router := mux.NewRouter() 251 252 switch web.SiteMode { 253 case web.SiteModeOffline: 254 log.Info("Serving OFFLINE web app") 255 case web.SiteModeSetup: 256 log.Info("Serving SETUP web app") 257 router.HandleFunc("/setup", database.Create).Methods("POST", "OPTIONS") 258 case web.SiteModeBadDB: 259 log.Info("Serving BAD DATABASE web app") 260 default: 261 log.Info("Starting web app") 262 } 263 264 router.HandleFunc("/robots.txt", GetRobots).Methods("GET", "OPTIONS") 265 router.HandleFunc("/sitemap.xml", GetSitemap).Methods("GET", "OPTIONS") 266 router.HandleFunc("/{rest:.*}", web.EmberHandler) 267 268 return router 269 }