2015-06-14 23:53:32 -08:00
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
package web
import (
l4g "code.google.com/p/log4go"
"fmt"
"github.com/gorilla/mux"
"github.com/mattermost/platform/api"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
"github.com/mssola/user_agent"
"gopkg.in/fsnotify.v1"
"html/template"
"net/http"
"strconv"
"strings"
)
var Templates * template . Template
type HtmlTemplatePage api . Page
func NewHtmlTemplatePage ( templateName string , title string ) * HtmlTemplatePage {
if len ( title ) > 0 {
title = utils . Cfg . ServiceSettings . SiteName + " - " + title
}
props := make ( map [ string ] string )
props [ "AnalyticsUrl" ] = utils . Cfg . ServiceSettings . AnalyticsUrl
2015-08-20 17:02:47 -07:00
props [ "ProfileHeight" ] = fmt . Sprintf ( "%v" , utils . Cfg . ImageSettings . ProfileHeight )
props [ "ProfileWidth" ] = fmt . Sprintf ( "%v" , utils . Cfg . ImageSettings . ProfileWidth )
2015-06-14 23:53:32 -08:00
return & HtmlTemplatePage { TemplateName : templateName , Title : title , SiteName : utils . Cfg . ServiceSettings . SiteName , Props : props }
}
func ( me * HtmlTemplatePage ) Render ( c * api . Context , w http . ResponseWriter ) {
if err := Templates . ExecuteTemplate ( w , me . TemplateName , me ) ; err != nil {
c . SetUnknownError ( me . TemplateName , err . Error ( ) )
}
}
func InitWeb ( ) {
l4g . Debug ( "Initializing web routes" )
2015-07-08 11:50:10 -04:00
mainrouter := api . Srv . Router
2015-06-14 23:53:32 -08:00
staticDir := utils . FindDir ( "web/static" )
l4g . Debug ( "Using static directory at %v" , staticDir )
2015-07-08 11:50:10 -04:00
mainrouter . PathPrefix ( "/static/" ) . Handler ( http . StripPrefix ( "/static/" , http . FileServer ( http . Dir ( staticDir ) ) ) )
mainrouter . Handle ( "/" , api . AppHandlerIndependent ( root ) ) . Methods ( "GET" )
mainrouter . Handle ( "/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}" , api . AppHandler ( login ) ) . Methods ( "GET" )
mainrouter . Handle ( "/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/" , api . AppHandler ( login ) ) . Methods ( "GET" )
mainrouter . Handle ( "/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/login" , api . AppHandler ( login ) ) . Methods ( "GET" )
2015-07-15 12:48:50 -04:00
2015-08-13 12:03:47 -04:00
// Bug in gorilla.mux prevents us from using regex here.
2015-07-22 10:12:28 -04:00
mainrouter . Handle ( "/{team}/login/{service}" , api . AppHandler ( loginWithOAuth ) ) . Methods ( "GET" )
2015-07-17 09:47:25 -04:00
mainrouter . Handle ( "/login/{service:[A-Za-z]+}/complete" , api . AppHandlerIndependent ( loginCompleteOAuth ) ) . Methods ( "GET" )
2015-07-15 12:48:50 -04:00
2015-07-08 11:50:10 -04:00
mainrouter . Handle ( "/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/logout" , api . AppHandler ( logout ) ) . Methods ( "GET" )
mainrouter . Handle ( "/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/reset_password" , api . AppHandler ( resetPassword ) ) . Methods ( "GET" )
2015-08-13 12:03:47 -04:00
// Bug in gorilla.mux prevents us from using regex here.
2015-07-08 11:50:10 -04:00
mainrouter . Handle ( "/{team}/channels/{channelname}" , api . UserRequired ( getChannel ) ) . Methods ( "GET" )
// Anything added here must have an _ in it so it does not conflict with team names
mainrouter . Handle ( "/signup_team_complete/" , api . AppHandlerIndependent ( signupTeamComplete ) ) . Methods ( "GET" )
mainrouter . Handle ( "/signup_user_complete/" , api . AppHandlerIndependent ( signupUserComplete ) ) . Methods ( "GET" )
mainrouter . Handle ( "/signup_team_confirm/" , api . AppHandlerIndependent ( signupTeamConfirm ) ) . Methods ( "GET" )
2015-07-15 12:48:50 -04:00
2015-08-13 12:03:47 -04:00
// Bug in gorilla.mux prevents us from using regex here.
2015-07-22 10:12:28 -04:00
mainrouter . Handle ( "/{team}/signup/{service}" , api . AppHandler ( signupWithOAuth ) ) . Methods ( "GET" )
2015-07-17 09:47:25 -04:00
mainrouter . Handle ( "/signup/{service:[A-Za-z]+}/complete" , api . AppHandlerIndependent ( signupCompleteOAuth ) ) . Methods ( "GET" )
2015-07-15 12:48:50 -04:00
2015-07-08 11:50:10 -04:00
mainrouter . Handle ( "/verify_email" , api . AppHandlerIndependent ( verifyEmail ) ) . Methods ( "GET" )
mainrouter . Handle ( "/find_team" , api . AppHandlerIndependent ( findTeam ) ) . Methods ( "GET" )
mainrouter . Handle ( "/signup_team" , api . AppHandlerIndependent ( signup ) ) . Methods ( "GET" )
2015-06-14 23:53:32 -08:00
watchAndParseTemplates ( )
}
func watchAndParseTemplates ( ) {
templatesDir := utils . FindDir ( "web/templates" )
l4g . Debug ( "Parsing templates at %v" , templatesDir )
var err error
if Templates , err = template . ParseGlob ( templatesDir + "*.html" ) ; err != nil {
l4g . Error ( "Failed to parse templates %v" , err )
}
watcher , err := fsnotify . NewWatcher ( )
if err != nil {
l4g . Error ( "Failed to create directory watcher %v" , err )
}
go func ( ) {
for {
select {
case event := <- watcher . Events :
if event . Op & fsnotify . Write == fsnotify . Write {
l4g . Info ( "Re-parsing templates because of modified file %v" , event . Name )
if Templates , err = template . ParseGlob ( templatesDir + "*.html" ) ; err != nil {
l4g . Error ( "Failed to parse templates %v" , err )
}
}
case err := <- watcher . Errors :
l4g . Error ( "Failed in directory watcher %v" , err )
}
}
} ( )
err = watcher . Add ( templatesDir )
if err != nil {
l4g . Error ( "Failed to add directory to watcher %v" , err )
}
}
var browsersNotSupported string = "MSIE/8;MSIE/9;Internet Explorer/8;Internet Explorer/9"
func CheckBrowserCompatability ( c * api . Context , r * http . Request ) bool {
ua := user_agent . New ( r . UserAgent ( ) )
bname , bversion := ua . Browser ( )
browsers := strings . Split ( browsersNotSupported , ";" )
for _ , browser := range browsers {
version := strings . Split ( browser , "/" )
if strings . HasPrefix ( bname , version [ 0 ] ) && strings . HasPrefix ( bversion , version [ 1 ] ) {
c . Err = model . NewAppError ( "CheckBrowserCompatability" , "Your current browser is not supported, please upgrade to one of the following browsers: Google Chrome 21 or higher, Internet Explorer 10 or higher, FireFox 14 or higher" , "" )
return false
}
}
return true
}
func root ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
if ! CheckBrowserCompatability ( c , r ) {
return
}
if len ( c . Session . UserId ) == 0 {
2015-07-08 11:50:10 -04:00
page := NewHtmlTemplatePage ( "signup_team" , "Signup" )
page . Render ( c , w )
2015-06-14 23:53:32 -08:00
} else {
page := NewHtmlTemplatePage ( "home" , "Home" )
2015-07-08 11:50:10 -04:00
page . Props [ "TeamURL" ] = c . GetTeamURL ( )
2015-06-14 23:53:32 -08:00
page . Render ( c , w )
}
}
2015-07-08 11:50:10 -04:00
func signup ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
2015-06-14 23:53:32 -08:00
if ! CheckBrowserCompatability ( c , r ) {
return
}
2015-07-08 11:50:10 -04:00
page := NewHtmlTemplatePage ( "signup_team" , "Signup" )
page . Render ( c , w )
}
func login ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
if ! CheckBrowserCompatability ( c , r ) {
return
}
params := mux . Vars ( r )
teamName := params [ "team" ]
2015-06-14 23:53:32 -08:00
2015-07-08 11:50:10 -04:00
var team * model . Team
if tResult := <- api . Srv . Store . Team ( ) . GetByName ( teamName ) ; tResult . Err != nil {
l4g . Error ( "Couldn't find team name=%v, teamURL=%v, err=%v" , teamName , c . GetTeamURL ( ) , tResult . Err . Message )
// This should probably do somthing nicer
http . Redirect ( w , r , "http://" + r . Host , http . StatusTemporaryRedirect )
return
2015-06-14 23:53:32 -08:00
} else {
2015-07-08 11:50:10 -04:00
team = tResult . Data . ( * model . Team )
}
2015-06-14 23:53:32 -08:00
2015-07-08 11:50:10 -04:00
// If we are already logged into this team then go to home
if len ( c . Session . UserId ) != 0 && c . Session . TeamId == team . Id {
page := NewHtmlTemplatePage ( "home" , "Home" )
page . Props [ "TeamURL" ] = c . GetTeamURL ( )
page . Render ( c , w )
return
2015-06-14 23:53:32 -08:00
}
page := NewHtmlTemplatePage ( "login" , "Login" )
2015-07-08 11:50:10 -04:00
page . Props [ "TeamDisplayName" ] = team . DisplayName
2015-06-14 23:53:32 -08:00
page . Props [ "TeamName" ] = teamName
2015-07-22 15:32:39 -04:00
page . Props [ "AuthServices" ] = model . ArrayToJson ( utils . GetAllowedAuthServices ( ) )
2015-06-14 23:53:32 -08:00
page . Render ( c , w )
}
func signupTeamConfirm ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
email := r . FormValue ( "email" )
page := NewHtmlTemplatePage ( "signup_team_confirm" , "Signup Email Sent" )
page . Props [ "Email" ] = email
page . Render ( c , w )
}
func signupTeamComplete ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
data := r . FormValue ( "d" )
hash := r . FormValue ( "h" )
if ! model . ComparePassword ( hash , fmt . Sprintf ( "%v:%v" , data , utils . Cfg . ServiceSettings . InviteSalt ) ) {
c . Err = model . NewAppError ( "signupTeamComplete" , "The signup link does not appear to be valid" , "" )
return
}
props := model . MapFromJson ( strings . NewReader ( data ) )
t , err := strconv . ParseInt ( props [ "time" ] , 10 , 64 )
if err != nil || model . GetMillis ( ) - t > 1000 * 60 * 60 { // one hour
c . Err = model . NewAppError ( "signupTeamComplete" , "The signup link has expired" , "" )
return
}
page := NewHtmlTemplatePage ( "signup_team_complete" , "Complete Team Sign Up" )
page . Props [ "Email" ] = props [ "email" ]
page . Props [ "Data" ] = data
page . Props [ "Hash" ] = hash
page . Render ( c , w )
}
func signupUserComplete ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
id := r . FormValue ( "id" )
data := r . FormValue ( "d" )
hash := r . FormValue ( "h" )
var props map [ string ] string
if len ( id ) > 0 {
props = make ( map [ string ] string )
if result := <- api . Srv . Store . Team ( ) . Get ( id ) ; result . Err != nil {
c . Err = result . Err
return
} else {
team := result . Data . ( * model . Team )
if ! ( team . Type == model . TEAM_OPEN || ( team . Type == model . TEAM_INVITE && len ( team . AllowedDomains ) > 0 ) ) {
c . Err = model . NewAppError ( "signupUserComplete" , "The team type doesn't allow open invites" , "id=" + id )
return
}
props [ "email" ] = ""
2015-07-08 11:50:10 -04:00
props [ "display_name" ] = team . DisplayName
2015-06-14 23:53:32 -08:00
props [ "name" ] = team . Name
props [ "id" ] = team . Id
data = model . MapToJson ( props )
hash = ""
}
} else {
if ! model . ComparePassword ( hash , fmt . Sprintf ( "%v:%v" , data , utils . Cfg . ServiceSettings . InviteSalt ) ) {
c . Err = model . NewAppError ( "signupTeamComplete" , "The signup link does not appear to be valid" , "" )
return
}
props = model . MapFromJson ( strings . NewReader ( data ) )
t , err := strconv . ParseInt ( props [ "time" ] , 10 , 64 )
if err != nil || model . GetMillis ( ) - t > 1000 * 60 * 60 * 48 { // 48 hour
c . Err = model . NewAppError ( "signupTeamComplete" , "The signup link has expired" , "" )
return
}
}
page := NewHtmlTemplatePage ( "signup_user_complete" , "Complete User Sign Up" )
page . Props [ "Email" ] = props [ "email" ]
2015-07-08 11:50:10 -04:00
page . Props [ "TeamDisplayName" ] = props [ "display_name" ]
2015-06-14 23:53:32 -08:00
page . Props [ "TeamName" ] = props [ "name" ]
page . Props [ "TeamId" ] = props [ "id" ]
page . Props [ "Data" ] = data
page . Props [ "Hash" ] = hash
2015-07-22 15:32:39 -04:00
page . Props [ "AuthServices" ] = model . ArrayToJson ( utils . GetAllowedAuthServices ( ) )
2015-06-14 23:53:32 -08:00
page . Render ( c , w )
}
func logout ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
api . Logout ( c , w , r )
2015-07-08 11:50:10 -04:00
http . Redirect ( w , r , c . GetTeamURL ( ) , http . StatusFound )
2015-06-14 23:53:32 -08:00
}
func getChannel ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
params := mux . Vars ( r )
2015-07-08 11:50:10 -04:00
name := params [ "channelname" ]
2015-06-14 23:53:32 -08:00
var channelId string
if result := <- api . Srv . Store . Channel ( ) . CheckPermissionsToByName ( c . Session . TeamId , name , c . Session . UserId ) ; result . Err != nil {
c . Err = result . Err
return
} else {
channelId = result . Data . ( string )
}
if len ( channelId ) == 0 {
if strings . Index ( name , "__" ) > 0 {
// It's a direct message channel that doesn't exist yet so let's create it
ids := strings . Split ( name , "__" )
otherUserId := ""
if ids [ 0 ] == c . Session . UserId {
otherUserId = ids [ 1 ]
} else {
otherUserId = ids [ 0 ]
}
2015-06-29 09:07:13 -04:00
if sc , err := api . CreateDirectChannel ( c , otherUserId ) ; err != nil {
2015-06-14 23:53:32 -08:00
api . Handle404 ( w , r )
return
} else {
channelId = sc . Id
}
} else {
// lets make sure the user is valid
if result := <- api . Srv . Store . User ( ) . Get ( c . Session . UserId ) ; result . Err != nil {
c . Err = result . Err
c . RemoveSessionCookie ( w )
l4g . Error ( "Error in getting users profile for id=%v forcing logout" , c . Session . UserId )
return
}
2015-07-06 13:14:51 -07:00
//api.Handle404(w, r)
//Bad channel urls just redirect to the town-square for now
2015-07-09 13:59:19 -04:00
2015-07-08 11:50:10 -04:00
http . Redirect ( w , r , c . GetTeamURL ( ) + "/channels/town-square" , http . StatusFound )
2015-06-14 23:53:32 -08:00
return
}
}
var team * model . Team
if tResult := <- api . Srv . Store . Team ( ) . Get ( c . Session . TeamId ) ; tResult . Err != nil {
c . Err = tResult . Err
return
} else {
team = tResult . Data . ( * model . Team )
}
page := NewHtmlTemplatePage ( "channel" , "" )
2015-07-08 11:50:10 -04:00
page . Title = name + " - " + team . DisplayName + " " + page . SiteName
page . Props [ "TeamDisplayName" ] = team . DisplayName
2015-06-14 23:53:32 -08:00
page . Props [ "TeamType" ] = team . Type
2015-06-18 10:40:46 -04:00
page . Props [ "TeamId" ] = team . Id
2015-06-14 23:53:32 -08:00
page . Props [ "ChannelName" ] = name
page . Props [ "ChannelId" ] = channelId
page . Props [ "UserId" ] = c . Session . UserId
page . Render ( c , w )
}
func verifyEmail ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
resend := r . URL . Query ( ) . Get ( "resend" )
2015-07-29 16:17:20 -04:00
name := r . URL . Query ( ) . Get ( "teamname" )
2015-06-14 23:53:32 -08:00
email := r . URL . Query ( ) . Get ( "email" )
hashedId := r . URL . Query ( ) . Get ( "hid" )
userId := r . URL . Query ( ) . Get ( "uid" )
2015-07-29 16:17:20 -04:00
var team * model . Team
if result := <- api . Srv . Store . Team ( ) . GetByName ( name ) ; result . Err != nil {
c . Err = result . Err
return
} else {
team = result . Data . ( * model . Team )
}
2015-06-14 23:53:32 -08:00
2015-07-29 16:17:20 -04:00
if resend == "true" {
if result := <- api . Srv . Store . User ( ) . GetByEmail ( team . Id , email ) ; result . Err != nil {
2015-06-14 23:53:32 -08:00
c . Err = result . Err
return
} else {
user := result . Data . ( * model . User )
2015-07-30 13:42:27 -04:00
api . FireAndForgetVerifyEmail ( user . Id , user . Email , team . Name , team . DisplayName , c . GetSiteURL ( ) , c . GetTeamURLFromTeam ( team ) )
2015-06-14 23:53:32 -08:00
http . Redirect ( w , r , "/" , http . StatusFound )
return
}
}
var isVerified string
if len ( userId ) != 26 {
isVerified = "false"
} else if len ( hashedId ) == 0 {
isVerified = "false"
} else if model . ComparePassword ( hashedId , userId ) {
isVerified = "true"
if c . Err = ( <- api . Srv . Store . User ( ) . VerifyEmail ( userId ) ) . Err ; c . Err != nil {
return
} else {
c . LogAudit ( "" )
}
} else {
isVerified = "false"
}
page := NewHtmlTemplatePage ( "verify" , "Email Verified" )
page . Props [ "IsVerified" ] = isVerified
2015-07-29 16:17:20 -04:00
page . Props [ "TeamURL" ] = c . GetTeamURLFromTeam ( team )
page . Props [ "UserEmail" ] = email
2015-06-14 23:53:32 -08:00
page . Render ( c , w )
}
func findTeam ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
page := NewHtmlTemplatePage ( "find_team" , "Find Team" )
page . Render ( c , w )
}
func resetPassword ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
isResetLink := true
hash := r . URL . Query ( ) . Get ( "h" )
data := r . URL . Query ( ) . Get ( "d" )
2015-07-08 11:50:10 -04:00
params := mux . Vars ( r )
teamName := params [ "team" ]
2015-06-14 23:53:32 -08:00
if len ( hash ) == 0 || len ( data ) == 0 {
isResetLink = false
} else {
if ! model . ComparePassword ( hash , fmt . Sprintf ( "%v:%v" , data , utils . Cfg . ServiceSettings . ResetSalt ) ) {
c . Err = model . NewAppError ( "resetPassword" , "The reset link does not appear to be valid" , "" )
return
}
props := model . MapFromJson ( strings . NewReader ( data ) )
t , err := strconv . ParseInt ( props [ "time" ] , 10 , 64 )
if err != nil || model . GetMillis ( ) - t > 1000 * 60 * 60 { // one hour
c . Err = model . NewAppError ( "resetPassword" , "The signup link has expired" , "" )
return
}
}
2015-07-08 11:50:10 -04:00
teamDisplayName := "Developer/Beta"
var team * model . Team
if tResult := <- api . Srv . Store . Team ( ) . GetByName ( teamName ) ; tResult . Err != nil {
c . Err = tResult . Err
return
} else {
team = tResult . Data . ( * model . Team )
}
2015-06-14 23:53:32 -08:00
2015-07-08 11:50:10 -04:00
if team != nil {
teamDisplayName = team . DisplayName
2015-06-14 23:53:32 -08:00
}
page := NewHtmlTemplatePage ( "password_reset" , "" )
page . Title = "Reset Password - " + page . SiteName
2015-07-08 11:50:10 -04:00
page . Props [ "TeamDisplayName" ] = teamDisplayName
2015-06-14 23:53:32 -08:00
page . Props [ "Hash" ] = hash
page . Props [ "Data" ] = data
2015-07-08 11:50:10 -04:00
page . Props [ "TeamName" ] = teamName
2015-06-14 23:53:32 -08:00
page . Props [ "IsReset" ] = strconv . FormatBool ( isResetLink )
page . Render ( c , w )
}
2015-07-15 12:48:50 -04:00
2015-07-17 09:47:25 -04:00
func signupWithOAuth ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
params := mux . Vars ( r )
service := params [ "service" ]
2015-07-22 12:13:45 -04:00
teamName := params [ "team" ]
if len ( teamName ) == 0 {
c . Err = model . NewAppError ( "signupWithOAuth" , "Invalid team name" , "team_name=" + teamName )
c . Err . StatusCode = http . StatusBadRequest
return
}
hash := r . URL . Query ( ) . Get ( "h" )
var team * model . Team
if result := <- api . Srv . Store . Team ( ) . GetByName ( teamName ) ; result . Err != nil {
c . Err = result . Err
return
} else {
team = result . Data . ( * model . Team )
}
if api . IsVerifyHashRequired ( nil , team , hash ) {
data := r . URL . Query ( ) . Get ( "d" )
props := model . MapFromJson ( strings . NewReader ( data ) )
if ! model . ComparePassword ( hash , fmt . Sprintf ( "%v:%v" , data , utils . Cfg . ServiceSettings . InviteSalt ) ) {
2015-07-22 15:05:20 -04:00
c . Err = model . NewAppError ( "signupWithOAuth" , "The signup link does not appear to be valid" , "" )
2015-07-22 12:13:45 -04:00
return
}
t , err := strconv . ParseInt ( props [ "time" ] , 10 , 64 )
if err != nil || model . GetMillis ( ) - t > 1000 * 60 * 60 * 48 { // 48 hours
2015-07-22 15:05:20 -04:00
c . Err = model . NewAppError ( "signupWithOAuth" , "The signup link has expired" , "" )
2015-07-22 12:13:45 -04:00
return
}
if team . Id != props [ "id" ] {
2015-07-22 15:05:20 -04:00
c . Err = model . NewAppError ( "signupWithOAuth" , "Invalid team name" , data )
2015-07-22 12:13:45 -04:00
return
}
}
2015-07-15 12:48:50 -04:00
2015-07-17 09:47:25 -04:00
redirectUri := c . GetSiteURL ( ) + "/signup/" + service + "/complete"
2015-07-15 12:48:50 -04:00
2015-08-14 08:43:49 -04:00
api . GetAuthorizationCode ( c , w , r , teamName , service , redirectUri , "" )
2015-07-15 12:48:50 -04:00
}
2015-07-17 09:47:25 -04:00
func signupCompleteOAuth ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
params := mux . Vars ( r )
service := params [ "service" ]
2015-07-15 12:48:50 -04:00
code := r . URL . Query ( ) . Get ( "code" )
state := r . URL . Query ( ) . Get ( "state" )
2015-08-14 08:43:49 -04:00
uri := c . GetSiteURL ( ) + "/signup/" + service + "/complete"
2015-07-17 09:47:25 -04:00
2015-08-14 08:43:49 -04:00
if body , team , err := api . AuthorizeOAuthUser ( service , code , state , uri ) ; err != nil {
2015-07-15 12:48:50 -04:00
c . Err = err
return
} else {
2015-07-17 09:47:25 -04:00
var user * model . User
if service == model . USER_AUTH_SERVICE_GITLAB {
glu := model . GitLabUserFromJson ( body )
user = model . UserFromGitLabUser ( glu )
2015-08-13 12:03:47 -04:00
} else if service == model . USER_AUTH_SERVICE_GOOGLE {
gu := model . GoogleUserFromJson ( body )
user = model . UserFromGoogleUser ( gu )
2015-07-17 09:47:25 -04:00
}
if user == nil {
c . Err = model . NewAppError ( "signupCompleteOAuth" , "Could not create user out of " + service + " user object" , "" )
return
}
2015-07-22 11:26:55 -04:00
if result := <- api . Srv . Store . User ( ) . GetByAuth ( team . Id , user . AuthData , service ) ; result . Err == nil {
c . Err = model . NewAppError ( "signupCompleteOAuth" , "This " + service + " account has already been used to sign up for team " + team . DisplayName , "email=" + user . Email )
return
}
2015-07-22 11:14:51 -04:00
if result := <- api . Srv . Store . User ( ) . GetByEmail ( team . Id , user . Email ) ; result . Err == nil {
c . Err = model . NewAppError ( "signupCompleteOAuth" , "Team " + team . DisplayName + " already has a user with the email address attached to your " + service + " account" , "email=" + user . Email )
return
}
2015-07-22 10:12:28 -04:00
user . TeamId = team . Id
2015-07-15 12:48:50 -04:00
page := NewHtmlTemplatePage ( "signup_user_oauth" , "Complete User Sign Up" )
page . Props [ "User" ] = user . ToJson ( )
2015-07-22 10:12:28 -04:00
page . Props [ "TeamName" ] = team . Name
page . Props [ "TeamDisplayName" ] = team . DisplayName
2015-07-15 12:48:50 -04:00
page . Render ( c , w )
}
}
2015-07-17 09:47:25 -04:00
func loginWithOAuth ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
params := mux . Vars ( r )
service := params [ "service" ]
2015-07-22 12:13:45 -04:00
teamName := params [ "team" ]
2015-08-14 08:43:49 -04:00
loginHint := r . URL . Query ( ) . Get ( "login_hint" )
2015-07-22 12:13:45 -04:00
if len ( teamName ) == 0 {
c . Err = model . NewAppError ( "loginWithOAuth" , "Invalid team name" , "team_name=" + teamName )
c . Err . StatusCode = http . StatusBadRequest
return
}
// Make sure team exists
if result := <- api . Srv . Store . Team ( ) . GetByName ( teamName ) ; result . Err != nil {
c . Err = result . Err
return
}
2015-07-15 12:48:50 -04:00
2015-07-17 09:47:25 -04:00
redirectUri := c . GetSiteURL ( ) + "/login/" + service + "/complete"
2015-07-15 12:48:50 -04:00
2015-08-14 08:43:49 -04:00
api . GetAuthorizationCode ( c , w , r , teamName , service , redirectUri , loginHint )
2015-07-15 12:48:50 -04:00
}
2015-07-17 09:47:25 -04:00
func loginCompleteOAuth ( c * api . Context , w http . ResponseWriter , r * http . Request ) {
params := mux . Vars ( r )
service := params [ "service" ]
2015-07-15 12:48:50 -04:00
code := r . URL . Query ( ) . Get ( "code" )
state := r . URL . Query ( ) . Get ( "state" )
2015-08-14 08:43:49 -04:00
uri := c . GetSiteURL ( ) + "/login/" + service + "/complete"
2015-07-17 09:47:25 -04:00
2015-08-14 08:43:49 -04:00
if body , team , err := api . AuthorizeOAuthUser ( service , code , state , uri ) ; err != nil {
2015-07-15 12:48:50 -04:00
c . Err = err
return
} else {
2015-07-17 09:47:25 -04:00
authData := ""
if service == model . USER_AUTH_SERVICE_GITLAB {
glu := model . GitLabUserFromJson ( body )
authData = glu . GetAuthData ( )
2015-08-14 08:43:49 -04:00
} else if service == model . USER_AUTH_SERVICE_GOOGLE {
gu := model . GoogleUserFromJson ( body )
authData = gu . GetAuthData ( )
2015-07-17 09:47:25 -04:00
}
if len ( authData ) == 0 {
c . Err = model . NewAppError ( "loginCompleteOAuth" , "Could not parse auth data out of " + service + " user object" , "" )
return
}
2015-07-15 12:48:50 -04:00
var user * model . User
2015-07-22 10:12:28 -04:00
if result := <- api . Srv . Store . User ( ) . GetByAuth ( team . Id , authData , service ) ; result . Err != nil {
2015-07-15 12:48:50 -04:00
c . Err = result . Err
return
} else {
user = result . Data . ( * model . User )
api . Login ( c , w , r , user , "" )
if c . Err != nil {
return
}
root ( c , w , r )
}
}
}