1
package api
2

3
import (
4
    "fmt"
5
    "net/http"
6
    "time"
7

8
    "github.com/gin-gonic/gin"
9

10
    "github.com/earaujoassis/space/models"
11
    "github.com/earaujoassis/space/oauth"
12
    "github.com/earaujoassis/space/policy"
13
    "github.com/earaujoassis/space/security"
14
    "github.com/earaujoassis/space/services"
15
    "github.com/earaujoassis/space/services/logger"
16
    "github.com/earaujoassis/space/utils"
17
)
18

19
// exposeSessionsRoutes defines and exposes HTTP routes for a given gin.RouterGroup
20
//      in the REST API escope, for the sessions resource
21 0
func exposeSessionsRoutes(router *gin.RouterGroup) {
22 0
    sessionsRoutes := router.Group("/sessions")
23
    {
24
        // Requires X-Requested-By and Origin (same-origin policy)
25 0
        sessionsRoutes.POST("/create", requiresConformance, func(c *gin.Context) {
26 0
            var holder = c.PostForm("holder")
27 0
            var state = c.PostForm("state")
28

29 0
            var IP = c.Request.RemoteAddr
30 0
            var userID = IP
31 0
            var statusSignInAttempts = policy.SignInAttemptStatus(IP)
32

33 0
            if !security.ValidEmail(holder) && !security.ValidRandomString(holder) {
34 0
                c.JSON(http.StatusBadRequest, utils.H{
35 0
                    "_status":  "error",
36 0
                    "_message": "Session was not created",
37 0
                    "error": "must use valid holder string",
38 0
                })
39 0
                return
40
            }
41

42 0
            user := services.FindUserByAccountHolder(holder)
43 0
            client := services.FindOrCreateClient(services.DefaultClient)
44 0
            if user.ID != 0 && statusSignInAttempts != policy.Blocked {
45 0
                userID = user.UUID
46 0
                statusSignInAttempts = policy.SignInAttemptStatus(userID)
47 0
                if user.Authentic(c.PostForm("password"), c.PostForm("passcode")) && statusSignInAttempts != policy.Blocked {
48 0
                    session := services.CreateSession(user, client,
49 0
                        c.Request.RemoteAddr,
50 0
                        c.Request.UserAgent(),
51 0
                        models.PublicScope,
52 0
                        models.GrantToken)
53 0
                    if session.ID != 0 {
54 0
                        go logger.LogAction("session.created", utils.H{
55 0
                            "Email":     user.Email,
56 0
                            "FirstName": user.FirstName,
57 0
                            "IP":        session.IP,
58 0
                            "CreatedAt": session.CreatedAt.Format(time.RFC850),
59 0
                        })
60 0
                        policy.RegisterSuccessfulSignIn(user.UUID)
61 0
                        policy.RegisterSuccessfulSignIn(IP)
62 0
                        c.JSON(http.StatusOK, utils.H{
63 0
                            "_status":      "created",
64 0
                            "_message":     "Session was created",
65 0
                            "scope":        session.Scopes,
66 0
                            "grant_type":   "authorization_code",
67 0
                            "code":         session.Token,
68 0
                            "redirect_uri": "/session",
69 0
                            "client_id":    client.Key,
70 0
                            "state":        state,
71 0
                        })
72 0
                        return
73
                    }
74
                }
75
            }
76 0
            policy.RegisterSignInAttempt(userID)
77 0
            c.JSON(http.StatusBadRequest, utils.H{
78 0
                "_status":  "error",
79 0
                "_message": "Session was not created",
80 0
                "error":    oauth.AccessDenied,
81 0
                "attempts": statusSignInAttempts,
82 0
            })
83
        })
84

85
        // Requires X-Requested-By and Origin (same-origin policy)
86 0
        sessionsRoutes.POST("/magic", requiresConformance, func(c *gin.Context) {
87 0
            var holder = c.PostForm("holder")
88 0
            var next = c.PostForm("next")
89 0
            var state = c.PostForm("state")
90

91 0
            var host = fmt.Sprintf("%s://%s", scheme(c.Request), c.Request.Host)
92

93 0
            var IP = c.Request.RemoteAddr
94 0
            var userID = IP
95 0
            var statusSignInAttempts = policy.SignInAttemptStatus(IP)
96

97 0
            if !security.ValidEmail(holder) && !security.ValidRandomString(holder) {
98 0
                c.JSON(http.StatusBadRequest, utils.H{
99 0
                    "_status":  "error",
100 0
                    "_message": "Magic Session was not created",
101 0
                    "error": "must use valid holder string",
102 0
                })
103 0
                return
104
            }
105

106 0
            user := services.FindUserByAccountHolder(holder)
107 0
            client := services.FindOrCreateClient(services.DefaultClient)
108 0
            if user.ID != 0 && statusSignInAttempts != policy.Blocked {
109 0
                userID = user.UUID
110 0
                statusSignInAttempts = policy.SignInAttemptStatus(userID)
111 0
                if statusSignInAttempts != policy.Blocked {
112 0
                    session := services.CreateSession(user, client,
113 0
                        c.Request.RemoteAddr,
114 0
                        c.Request.UserAgent(),
115 0
                        models.PublicScope,
116 0
                        models.GrantToken)
117 0
                    if session.ID != 0 {
118 0
                        go logger.LogAction("session.magic", utils.H{
119 0
                            "Email":     user.Email,
120 0
                            "FirstName": user.FirstName,
121 0
                            "CreatedAt": session.CreatedAt.Format(time.RFC850),
122 0
                            "Callback": fmt.Sprintf("%s/session?client_id=%s&code=%s&grant_type=authorization_code&scope=%s&state=%s&_=%s",
123 0
                                host, client.Key, session.Token, session.Scopes, state, next),
124 0
                        })
125 0
                        policy.RegisterSuccessfulSignIn(user.UUID)
126 0
                        policy.RegisterSuccessfulSignIn(IP)
127 0
                        c.JSON(http.StatusNoContent, nil)
128 0
                        return
129
                    }
130
                }
131
            }
132 0
            policy.RegisterSignInAttempt(userID)
133 0
            c.JSON(http.StatusNoContent, nil)
134
        })
135

136
        // Authorization type: Basic (for OAuth clients use)
137 0
        sessionsRoutes.POST("/introspect", clientBasicAuthorization, func(c *gin.Context) {
138 0
            var token = c.PostForm("access_token")
139

140 0
            if !security.ValidToken(token) {
141 0
                c.JSON(http.StatusBadRequest, utils.H{
142 0
                    "_status":  "error",
143 0
                    "_message": "Session instropection failed",
144 0
                    "error": "must use valid token string",
145 0
                })
146 0
                return
147
            }
148

149 0
            session := services.FindSessionByToken(token, models.AccessToken)
150 0
            if session.ID == 0 {
151 0
                c.JSON(http.StatusUnauthorized, utils.H{
152 0
                    "_status":  "error",
153 0
                    "_message": "Session instropection failed",
154 0
                    "error": oauth.InvalidSession,
155 0
                })
156 0
                return
157
            }
158 0
            c.JSON(http.StatusOK, utils.H{
159 0
                "_status":  "success",
160 0
                "_message": "Session instropection fulfilled",
161 0
                "active":     true,
162 0
                "scope":      session.Scopes,
163 0
                "client_id":  session.Client.Key,
164 0
                "token_type": "Bearer",
165 0
            })
166
        })
167

168
        // Authorization type: Basic (for OAuth clients use)
169 0
        sessionsRoutes.POST("/invalidate", clientBasicAuthorization, func(c *gin.Context) {
170 0
            var token = c.PostForm("access_token")
171

172 0
            if !security.ValidToken(token) {
173 0
                c.JSON(http.StatusBadRequest, utils.H{
174 0
                    "_status":  "error",
175 0
                    "_message": "Session invalidation failed",
176 0
                    "error": "must use valid token string",
177 0
                })
178 0
                return
179
            }
180

181 0
            session := services.FindSessionByToken(token, models.AccessToken)
182 0
            if session.ID == 0 {
183 0
                c.JSON(http.StatusUnauthorized, utils.H{
184 0
                    "_status":  "error",
185 0
                    "_message": "Session invalidation failed",
186 0
                    "error": oauth.InvalidSession,
187 0
                })
188 0
                return
189
            }
190 0
            services.InvalidateSession(session)
191 0
            c.JSON(http.StatusOK, utils.H{
192 0
                "_status":    "deleted",
193 0
                "_message":   "Session was deleted (soft)",
194 0
                "active":     false,
195 0
                "scope":      session.Scopes,
196 0
                "client_id":  session.Client.Key,
197 0
                "token_type": "Bearer",
198 0
            })
199
        })
200
    }
201
}

Read our documentation on viewing source code .

Loading