[CODE lang="b4x" title="Main (jAPI.b4j)"]'Non-UI application (console / server application)
#Region Project Attributes
#CommandLineArgs:
#MergeLibraries: True
#End Region
' MySQL Connector
#AdditionalJar: mysql-connector-java-5.1.37-bin
'#AdditionalJar: postgresql-9.4.1207 ' PostgreSQL
'#AdditionalJar: jtds-1.3.1.jar ' SQL Server
Sub Process_Globals
Public srvr As Server
Public SERVER_PORT As Int
Public SSL_PORT As Int
Public ROOT_PATH As String
Public ROOT_URL As String
'Private ELEMENT_ROOT As Int
Public ELEMENT_CONTROLLER As Int
Public ELEMENT_ACTION As Int
Public ELEMENT_ID As Int
Public MAX_ELEMENTS As Int = 4
Public const VERSION As Float = 1.02
End Sub
Sub AppStart (Args() As String)
Dim config As Map = Utility.ReadConfig
SERVER_PORT = config.Get("ServerPort")
SSL_PORT = config.Get("SSLPort")
ROOT_PATH = config.Get("ROOT_PATH")
ROOT_URL = config.Get("ROOT_URL") & ":" & SERVER_PORT
srvr.Initialize("")
srvr.Port = SERVER_PORT
#If RELEASE
ConfigureSSL(SSL_PORT)
ROOT_URL = config.Get("ROOT_URL") & ":" & SSL_PORT
#End If
srvr.StaticFilesFolder = File.Combine(File.DirApp, "www")
srvr.SetStaticFilesOptions(CreateMap("dirAllowed": False))
If ROOT_PATH = "/" Then
srvr.AddHandler("", "HomeHandler", False) ' using subdomain?
'ELEMENT_ROOT = 0
ELEMENT_CONTROLLER = 1
ELEMENT_ACTION = 2
ELEMENT_ID = 3
Else
srvr.AddHandler(ROOT_PATH, "HomeHandler", False)
'ELEMENT_ROOT = 1
ELEMENT_CONTROLLER = 2
ELEMENT_ACTION = 3
ELEMENT_ID = 4
MAX_ELEMENTS = MAX_ELEMENTS + 1
End If
srvr.AddHandler(ROOT_PATH & "test/*", "TestHandler", False)
srvr.AddHandler(ROOT_PATH & "user/*", "UserHandler", False)
srvr.AddHandler(ROOT_PATH & "password/*", "PasswordHandler", False)
srvr.Start
Log($"API server (version = $1.2{VERSION}) is running on port ${srvr.Port}"$)
#If RELEASE
Log($"Response will be redirected to port ${srvr.SslPort}"$)
#End If
LogDebug($"Open the following URL from your web browser"$)
LogDebug(ROOT_URL)
StartMessageLoop
End Sub
Private Sub ConfigureSSL (SslPort As Int)
'example of SSL connector configuration
Dim ssl As SslConfiguration
ssl.Initialize
ssl.SetKeyStorePath("/etc/letsencrypt/live/api.puterise.com", "keystore.jks") 'path to keystore file
ssl.KeyStorePassword = "123456"
'ssl.KeyManagerPassword = "654321"
srvr.SetSslConfiguration(ssl, SslPort)
'add filter to redirect all traffic from http to https (optional)
srvr.AddFilter("/*", "HttpsFilter", False)
End Sub[/CODE]
[CODE lang="b4x" title="HttpsFilter (HttpsFilter.bas)"]'Filter class
Sub Class_Globals
End Sub
Public Sub Initialize
End Sub
'Return True to allow the request to proceed.
Public Sub Filter(req As ServletRequest, resp As ServletResponse) As Boolean
If req.Secure Then
Return True
Else
resp.SendRedirect(req.FullRequestURI.Replace("http:", "https:") _
.Replace(Main.srvr.Port, Main.srvr.SslPort))
Return False
End If
End Sub[/CODE]
[CODE lang="b4x" title="HomeHandler (HomeHandler.bas)"]'Handler class
Sub Class_Globals
End Sub
Public Sub Initialize
End Sub
Sub Handle(req As ServletRequest, resp As ServletResponse)
Dim settings As Map = Utility.ReadSettings
settings.Put("ROOT_URL", Main.ROOT_URL)
settings.Put("ROOT_PATH", Main.ROOT_PATH)
Dim strMain As String = Utility.ReadTextFile("main.html")
Dim strView As String = Utility.ReadTextFile("index.html")
strMain = Utility.BuildView(strMain, strView)
strMain = Utility.BuildHtml(strMain, settings)
Utility.ReturnHTML(strMain, resp)
End Sub[/CODE]
[CODE lang="b4x" title="UserHandler (UserHandler.bas)"]
'Handler class
Sub Class_Globals
Dim Request As ServletRequest
Dim Response As ServletResponse
Dim pool As ConnectionPool
End Sub
Public Sub Initialize
End Sub
Sub Handle(req As ServletRequest, resp As ServletResponse)
Request = req
Response = resp
Dim elements() As String = Regex.Split("/", req.RequestURI)
If elements.Length > Main.MAX_ELEMENTS Or elements.Length = 0 Then
Response.SendError(500, "Unknown method")
Return
Else If elements.Length - 1 = Main.ELEMENT_CONTROLLER Then
Dim settings As Map = Utility.ReadSettings
settings.Put("ROOT_URL", Main.ROOT_URL)
settings.Put("ROOT_PATH", Main.ROOT_PATH)
Dim strMain As String = Utility.ReadTextFile("main.html")
Dim strView As String = Utility.ReadTextFile("user.html")
strMain = Utility.BuildView(strMain, strView)
strMain = Utility.BuildHtml(strMain, settings)
Utility.ReturnHTML(strMain, Response)
Return
End If
Dim ActionList As List
ActionList.Initialize2(Array As String("register", "activate", "login", "getapikey", "gettoken", "getprofile", "view", "update"))
If ActionList.IndexOf(elements(Main.ELEMENT_ACTION)) > -1 Then
OpenConnection
End If
Select elements(Main.ELEMENT_ACTION)
Case "connect"
Utility.ReturnConnect(Response)
Case "register"
Register
Case "activate"
'If elements.Length < Main.MAX_ELEMENTS Then Return
If elements.Length - 1 = Main.ELEMENT_ID Then
Activate(elements(Main.ELEMENT_ID))
Else
Activate("")
End If
Case "login"
Login
Case "getapikey"
GetApiKey
Case "gettoken"
GetToken
Case "getprofile"
GetProfile
Case "view"
'If elements.Length < Main.MAX_ELEMENTS Then Return
If elements.Length - 1 = Main.ELEMENT_ID Then
Select elements(Main.ELEMENT_ID)
Case "all"
View("all")
Case Else
View(elements(Main.ELEMENT_ID))
End Select
Else
Response.SendError(500, "Unknown action")
End If
Case "update"
Update
Case Else
Response.SendError(500, "Unknown action")
Return
End Select
If ActionList.IndexOf(elements(Main.ELEMENT_ACTION)) > -1 Then
CloseConnection
End If
End Sub
Sub RequestData As Map
Try
Dim data As Map
Dim ins As InputStream = Request.InputStream
Dim tr As TextReader
tr.Initialize(ins)
Dim json As JSONParser
json.Initialize(tr.ReadAll)
data = json.NextObject
Catch
LogDebug("[User/RequestData] " & LastException)
End Try
Return data
End Sub
Sub OpenConnection
Try
Dim config As Map = Utility.ReadConfig
pool.Initialize(config.Get("DriverClass"), _
config.Get("JdbcUrl"), _
config.Get("User"), _
config.Get("Password"))
Dim jo As JavaObject = pool
Dim MaxPoolSize As Int = config.Get("MaxPoolSize")
jo.RunMethod("setMaxPoolSize", Array(MaxPoolSize))
Catch
LogDebug(LastException)
End Try
End Sub
Sub CloseConnection
If pool.IsInitialized Then pool.ClosePool
End Sub
Sub WriteErrorLog(Module As String, Message As String)
Dim con As SQL = pool.GetConnection
Try
Dim strSQL As String = $"INSERT
INTO tbl_error
(error_text)
SELECT ?"$
con.ExecNonQuery2(strSQL, Array As String("[" & Module & "]" & Message))
Catch
LogDebug(LastException)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub WriteUserLog(log_view As String, log_type As String, log_text As String, Log_User As String)
Dim con As SQL = pool.GetConnection
Try
Dim strSQL As String = $"INSERT INTO tbl_users_log
(log_view,
log_type,
log_text,
log_user)
SELECT ?, ?, ?, ?"$
con.ExecNonQuery2(strSQL, Array As String(log_view, log_type, log_text, Log_User))
Catch
Dim msg_text As String = "[Exception] " & LastException
WriteErrorLog("WriteUserLog", msg_text)
Utility.ReturnError("Error-Execute-Query", Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub Register
Dim con As SQL = pool.GetConnection
Dim msg_text As String
Try
Dim Map1 As Map = RequestData
If Map1 = Null Or Map1.IsInitialized = False Then
msg_text = "[Null Value]"
WriteUserLog("user/register", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
Dim eml As String = Map1.Get("eml")
Dim pwd As String = Map1.Get("pwd")
Dim name As String = Map1.Get("name")
If eml = "" Or pwd = "" Or name = "" Then
msg_text = "[Not set]"
WriteUserLog("user/register", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
Dim strSQL As String = $"SELECT
user_id
FROM tbl_users
WHERE user_email = ?"$
Dim result As ResultSet = con.ExecQuery2(strSQL, Array As String(eml))
If result.NextRow Then
msg_text = "[Email Used] " & eml
WriteUserLog("user/register", "fail", msg_text, 0)
Utility.ReturnError("Error-Email-Used", Response)
con.Close
Return
Else
Dim salt As String = Utility.MD5(Rnd(100001, 999999))
Dim hash As String = Utility.MD5(pwd & salt)
Dim code As String = Utility.MD5(salt & eml)
Dim key As String = Utility.SHA1(hash)
Dim flag As String = "M"
strSQL = $"INSERT INTO tbl_users
(user_email,
user_name,
user_hash,
user_salt,
user_api_key,
user_activation_code,
user_activation_flag)
VALUES (?, ?, ?, ?, ?, ?, ?)"$
con.ExecNonQuery2(strSQL, Array As String(eml, name, hash, salt, key, code, flag))
Dim user_id As Int = con.ExecQuerySingleResult("SELECT LAST_INSERT_ID()")
msg_text = "new user"
WriteUserLog("user/register", "success", msg_text, user_id)
SendEmail(name, eml, code)
Utility.ReturnSuccess("success", Response)
con.Close
Return
End If
Catch
msg_text = "[Exception] " & LastException
WriteErrorLog("user/register", msg_text)
Utility.ReturnError("Error-Execute-Query", Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub Activate(Code As String)
Dim con As SQL = pool.GetConnection
Dim msg_text As String
Dim strMain As String
Dim strSQL As String
Try
If Code = "" Then
strMain = $"<h1>Activation</h1>
<p>Invalid activation code!</p>"$
Utility.ReturnHTML(strMain, Response)
con.Close
Return
Else If Code = "vhbgroalh90akyyypt0ah3qjo5gpb0bx" Then ' Dummy Code
strMain = $"<h1>Activation</h1>
<p>Dummy activation code!</p>"$
Utility.ReturnHTML(strMain, Response)
con.Close
Return
Else
strSQL = $"SELECT
user_id
FROM tbl_users
WHERE user_activation_code = ?
AND user_activation_flag = 'M'"$
Dim result As ResultSet = con.ExecQuery2(strSQL, Array As String(Code))
If result.NextRow Then
' Update flag
strSQL = $"UPDATE tbl_users SET
user_activation_flag = 'R',
user_activated_at = now(),
user_active = 1
WHERE user_activation_code = ?
AND user_activation_flag = 'M'"$
con.ExecNonQuery2(strSQL, Array As String(Code))
msg_text = Code
WriteUserLog("user/activate", "success", msg_text, 0)
strMain = $"<h1>Activation</h1>
<p>Your account is now activated!</p>"$
Utility.ReturnHTML(strMain, Response)
con.Close
Return
Else
msg_text = "[Email Used] "
WriteUserLog("user/activate", "fail", msg_text, 0)
strMain = $"<h1>Activation</h1>
<p>Account Not found!</p>"$
Utility.ReturnHTML(strMain, Response)
con.Close
Return
End If
End If
Catch
WriteErrorLog("user/activate", "[Exception] " & LastException)
strMain = $"<h1>Activation</h1>
<p>An error occured!</p>"$
Utility.ReturnHTML(strMain, Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub Login
Dim con As SQL = pool.GetConnection
Dim msg_text As String
Dim strSQL As String
Try
Dim Map1 As Map = RequestData
If Map1 = Null Or Map1.IsInitialized = False Then
msg_text = "[Null Value]"
WriteUserLog("user/login", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
Dim eml As String = Map1.Get("eml")
Dim pwd As String = Map1.Get("pwd")
If eml = "" Or pwd = "" Then
msg_text = "[Not set]"
WriteUserLog("user/login", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
strSQL = $"SELECT
user_id AS `result`,
'success' AS `message`,
user_name,
user_email,
ifnull(user_location, '') AS user_location,
ifnull(user_token, '') AS user_token,
ifnull(user_api_key, '') AS user_api_key,
user_activation_flag
FROM tbl_users
WHERE user_email = ?
AND user_hash = md5(concat(?, user_salt))"$
Dim result As ResultSet = con.ExecQuery2(strSQL, Array As String(eml, pwd))
If result.NextRow Then
If result.GetString("user_activation_flag") = "M" Then
msg_text = "[Not Activated] " & eml
WriteUserLog("user/login", "fail", msg_text, result.GetInt("result"))
Utility.ReturnError("Error-Not-Activated", Response)
con.Close
Return
End If
' Update login status
strSQL = $"UPDATE tbl_users SET
user_login_count = user_login_count + 1,
user_last_login_at = now()
WHERE user_email = ?"$
con.ExecNonQuery2(strSQL, Array As String(eml))
Dim Map2 As Map
Map2.Initialize
For i = 0 To result.ColumnCount - 1
If result.GetColumnName(i) = "result" Then
Map2.Put("result", result.GetInt("result"))
Else
Map2.Put(result.GetColumnName(i), result.GetString2(i))
End If
Next
msg_text = eml
WriteUserLog("user/login", "success", msg_text, result.GetInt("result"))
Utility.ReturnJSON(Map2, Response)
Else
msg_text = "[Not Found/Wrong Password] " & eml
WriteUserLog("user/login", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Result", Response)
End If
Catch
msg_text = "[Exception] " & LastException
WriteErrorLog("user/login", msg_text)
Utility.ReturnError("Error-Execute-Query", Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub GetApiKey
Dim con As SQL = pool.GetConnection
Dim msg_text As String
Dim strSQL As String
Try
Dim Map1 As Map = RequestData
If Map1 = Null Or Map1.IsInitialized = False Then
msg_text = "[Null Value]"
WriteUserLog("user/getapikey", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
Dim eml As String = Map1.Get("eml")
Dim pwd As String = Map1.Get("pwd")
If eml = "" Or pwd = "" Then
msg_text = "[Not set]"
WriteUserLog("user/getapikey", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
strSQL = $"SELECT
user_id AS `result`,
'success' AS `message`,
ifnull(user_api_key, '') AS user_api_key
FROM tbl_users
WHERE user_email = ?
AND user_hash = md5(concat(?, user_salt))"$
Dim result As ResultSet = con.ExecQuery2(strSQL, Array As String(eml, pwd))
If result.NextRow Then
msg_text = "[Existing key] "
If result.GetString("user_api_key") = "" Then
Dim apikey As String = Utility.SHA1(Rnd(100001, 999999))
' Update apikey
strSQL = $"UPDATE tbl_users SET
user_api_key = ?,
user_last_login_at = now(),
modified_at = now()
WHERE user_email = ?"$
con.ExecNonQuery2(strSQL, Array As String(apikey, eml))
msg_text = "[New key] "
End If
Dim Map2 As Map
Map2.Initialize
Map2.Put("result", result.GetInt("result"))
Map2.Put("message", "success")
Map2.Put("user_api_key", apikey)
WriteUserLog("user/getapikey", "success", msg_text & eml, result.GetInt("result"))
Utility.ReturnJSON(Map2, Response)
Else
msg_text = "[Not Found] " & eml
WriteUserLog("user/getapikey", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Result", Response)
End If
Catch
msg_text = "[Exception] " & LastException
WriteErrorLog("user/getapikey", msg_text)
Utility.ReturnError("Error-Execute-Query", Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub GetToken
Dim con As SQL = pool.GetConnection
Dim msg_text As String
Dim strSQL As String
Try
Dim Map1 As Map = RequestData
If Map1 = Null Or Map1.IsInitialized = False Then
msg_text = "[Null Value]"
WriteUserLog("user/gettoken", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
Dim apikey As String = Map1.Get("key")
If apikey = "" Then
msg_text = "[Not set]"
WriteUserLog("user/gettoken", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
strSQL = $"SELECT
user_id AS `result`,
'success' AS `message`,
ifnull(user_token, '') AS user_token
FROM tbl_users
WHERE user_api_key = ?"$
Dim result As ResultSet = con.ExecQuery2(strSQL, Array As String(apikey))
If result.NextRow Then
Dim token As String = result.GetString("user_token")
msg_text = "[Existing token] "
If token = "" Then
Dim newtoken As String = Utility.SHA1(Rnd(100001, 999999))
' Update token
strSQL = $"UPDATE tbl_users SET
user_token = ?,
user_last_login_at = now(),
modified_at = now()
WHERE user_api_key = ?"$
con.ExecNonQuery2(strSQL, Array As String(newtoken, apikey))
token = newtoken
msg_text = "[New token] "
End If
Dim Map2 As Map
Map2.Initialize
Map2.Put("result", result.GetInt("result"))
Map2.Put("message", "success")
Map2.Put("user_token", token)
WriteUserLog("user/gettoken", "success", msg_text & "key: " & apikey, result.GetInt("result"))
Utility.ReturnJSON(Map2, Response)
Else
msg_text = "[Not Found] " & apikey
WriteUserLog("user/gettoken", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Result", Response)
End If
Catch
msg_text = "[Exception] " & LastException
WriteErrorLog("user/gettoken", msg_text)
Utility.ReturnError("Error-Execute-Query", Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub GetProfile
Dim con As SQL = pool.GetConnection
Dim result As ResultSet
Dim msg_text As String
Dim strSQL As String
Try
Dim Map1 As Map = RequestData
If Map1 = Null Or Map1.IsInitialized = False Then
msg_text = "[Null Value]"
WriteUserLog("user/view", "fail", msg_text, 0)
Utility.ReturnError("Error-Not-Authorized", Response)
If con <> Null And con.IsInitialized Then con.Close
Return
End If
Dim token As String = Map1.Get("token")
LogDebug(token)
If token = "" Then
Utility.ReturnError("Error-Not-Authorized", Response)
If con <> Null And con.IsInitialized Then con.Close
Return
End If
' Update last login
strSQL = $"UPDATE tbl_users SET
user_last_login_at = now()
WHERE user_token = ?"$
con.ExecNonQuery2(strSQL, Array As String(token))
' Check Login session token
strSQL = $"SELECT
user_id AS `result`,
'success' AS `message`,
user_name,
user_email,
ifnull(user_location, '') AS user_location
FROM tbl_users
WHERE user_token = ?"$
result = con.ExecQuery2(strSQL, Array As String(token))
Dim List2 As List
List2.Initialize
Do While result.NextRow
Dim Map2 As Map
Map2.Initialize
For i = 0 To result.ColumnCount - 1
If result.GetColumnName(i) = "result" Then
Map2.Put("result", result.GetInt("result"))
Else
Map2.Put(result.GetColumnName(i), result.GetString2(i))
End If
Next
List2.Add(Map2)
Loop
If List2.Size > 0 Then
Utility.ReturnJSON2(List2, Response)
Else
Utility.ReturnError("Error-Invalid-Token", Response)
End If
Catch
msg_text = "[Exception] " & LastException
WriteErrorLog("user/getprofile", msg_text)
Utility.ReturnError("Error-Execute-Query", Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub View(id As String)
Dim con As SQL = pool.GetConnection
Dim result As ResultSet
Dim msg_text As String
Dim strSQL As String
Try
If id = "" Then
Utility.ReturnError("Error-No-Value", Response)
If con <> Null And con.IsInitialized Then con.Close
Return
End If
Dim Map1 As Map = RequestData
If Map1 = Null Or Map1.IsInitialized = False Then
msg_text = "[Null Value]"
WriteUserLog("user/view", "fail", msg_text, 0)
Utility.ReturnError("Error-Not-Authorized", Response)
If con <> Null And con.IsInitialized Then con.Close
Return
End If
Dim token As String = Map1.Get("token")
LogDebug(token)
If token = "" Then
Utility.ReturnError("Error-Not-Authorized", Response)
If con <> Null And con.IsInitialized Then con.Close
Return
End If
' Check Login session token
strSQL = "SELECT user_id FROM tbl_users WHERE user_token = ?"
result = con.ExecQuery2(strSQL, Array As String(token))
If result.NextRow Then
strSQL = $"UPDATE tbl_users SET
user_last_login_at = now()
WHERE user_token = ?"$
con.ExecNonQuery2(strSQL, Array As String(token))
' Query users logged in within 10 minutes
strSQL = $"SELECT
user_id AS `result`,
'success' AS `message`,
user_name,
user_email,
ifnull(user_location, '') AS user_location,
CASE
WHEN (user_last_login_at > now()-600) THEN 'Y'
ELSE 'N' END AS `online`
FROM tbl_users
WHERE EXISTS
(SELECT user_id
FROM tbl_users
WHERE user_token = ?)"$
If id <> "all" Then
strSQL = strSQL & " AND user_id = ?"
' Check id is numeric?
result = con.ExecQuery2(strSQL, Array As String(token, id))
Else
result = con.ExecQuery2(strSQL, Array As String(token))
End If
Dim List2 As List
List2.Initialize
Do While result.NextRow
Dim Map2 As Map
Map2.Initialize
For i = 0 To result.ColumnCount - 1
If result.GetColumnName(i) = "result" Then
Map2.Put("result", result.GetInt("result"))
Else
Map2.Put(result.GetColumnName(i), result.GetString2(i))
End If
Next
List2.Add(Map2)
Loop
Utility.ReturnJSON2(List2, Response)
Else
Utility.ReturnError("Error-Invalid-Token", Response)
End If
Catch
msg_text = "[Exception] " & LastException
WriteErrorLog("user/view", msg_text)
Utility.ReturnError("Error-Execute-Query", Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
' only update own profile, edit other users is restricted
Sub Update
Dim con As SQL = pool.GetConnection
Dim result As ResultSet
Dim strSQL As String
Dim msg_text As String
Try
Dim Map1 As Map = RequestData
If Map1 = Null Or Map1.IsInitialized = False Then
msg_text = "[Null Value]"
WriteUserLog("user/update", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
Dim key As String = Map1.Get("key")
Dim token As String = Map1.Get("token")
Dim user_name As String = Map1.Get("user_name")
Dim user_location As String = Map1.Get("user_location")
If token = "" Or key = "" Then
Utility.ReturnError("Error-Not-Authorized", Response)
con.Close
Return
End If
If user_name = "" Or user_location = "" Then
msg_text = "[Not Set]"
WriteUserLog("user/update", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
' Check Login session token
strSQL = "SELECT user_id FROM tbl_users WHERE user_token = ?"
result = con.ExecQuery2(strSQL, Array As String(token))
If result.NextRow Then
msg_text = "key: " & key
strSQL = $"SELECT user_id AS result
FROM tbl_users
WHERE EXISTS (SELECT user_id FROM tbl_users WHERE user_api_key = ?)"$
result = con.ExecQuery2(strSQL, Array As String(key))
If result.NextRow Then
strSQL = $"UPDATE tbl_users SET
user_name = ?,
user_location = ?,
user_last_login_at = now(),
modified_at = now()
WHERE user_api_key = ?"$
con.ExecNonQuery2(strSQL, Array As String(user_name, user_location, key))
WriteUserLog("user/update", "success", msg_text, result.GetInt("result"))
Utility.ReturnSuccess("success", Response)
Else
WriteUserLog("user/update", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Result", Response)
End If
Else
Utility.ReturnError("Error-Invalid-Token", Response)
End If
Catch
msg_text = "[Exception] " & LastException
WriteErrorLog("user/update", msg_text)
Utility.ReturnError("Error-Execute-Query", Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub SendEmail(user_name As String, user_email As String, activation_code As String)
Dim smtp As SMTP
Try
Dim settings As Map = Utility.ReadSettings
Dim APP_TRADEMARK As String = settings.Get("APP_TRADEMARK")
Dim SMTP_USERNAME As String = settings.Get("SMTP_USERNAME")
Dim SMTP_PASSWORD As String = settings.Get("SMTP_PASSWORD")
Dim SMTP_SERVER As String = settings.Get("SMTP_SERVER")
Dim SMTP_USESSL As String = settings.Get("SMTP_USESSL")
Dim SMTP_PORT As Int = settings.Get("SMTP_PORT")
Dim ADMIN_EMAIL As String = settings.Get("ADMIN_EMAIL")
smtp.Initialize(SMTP_SERVER, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD, "SMTP")
If SMTP_USESSL.ToUpperCase = "TRUE" Then smtp.UseSSL = True Else smtp.UseSSL = False
smtp.HtmlBody = True
LogDebug("Sending email...")
smtp.Sender = SMTP_USERNAME
smtp.To.Add(user_email)
smtp.AuthMethod = smtp.AUTH_LOGIN
smtp.subject = APP_TRADEMARK
smtp.body = $"Hi ${user_name},<br />
Please click on this link to finish the registration process:<br />
<a href="${Main.ROOT_URL}/user/activate/${activation_code}"
id="activate-link" title="activate" target="_blank">${Main.ROOT_URL}/user/activate/${activation_code}</a><br />
<br />
If the link is not working, please copy the url to your browser.<br />
<br />
Regards,<br />
<em>${APP_TRADEMARK}</em>"$
LogDebug(smtp.body)
Dim sm As Object = smtp.Send
Wait For (sm) SMTP_MessageSent (Success As Boolean)
If Success Then
LogDebug("Message sent successfully")
Else
LogDebug("Error sending message")
LogDebug(LastException)
End If
'Notify site admin of new sign up
smtp.Sender = SMTP_USERNAME
smtp.To.Add(ADMIN_EMAIL)
smtp.AuthMethod = smtp.AUTH_LOGIN
smtp.HtmlBody = False
smtp.subject = "New registration"
smtp.body = $"Hi Admin,${CRLF}
${user_name} has registered using our app."$
Dim sm As Object = smtp.Send
Wait For (sm) SMTP_MessageSent (Success As Boolean)
If Success Then
LogDebug("Message sent to Admin successfully")
Else
LogDebug("Error sending message to Admin")
LogDebug(LastException)
End If
Catch
LogDebug(LastException)
Utility.ReturnError("Error-Send-Email", Response)
End Try
End Sub[/CODE]
[CODE lang="b4x" title="PasswordHandler (PasswordHandler.bas)"]
'Handler class
Sub Class_Globals
Dim Request As ServletRequest
Dim Response As ServletResponse
Dim pool As ConnectionPool
End Sub
Public Sub Initialize
End Sub
Sub Handle(req As ServletRequest, resp As ServletResponse)
Request = req
Response = resp
Dim elements() As String = Regex.Split("/", req.RequestURI)
If elements.Length > Main.MAX_ELEMENTS Or elements.Length = 0 Then
Response.SendError(500, "Unknown method")
Return
Else If elements.Length - 1 = Main.ELEMENT_CONTROLLER Then
Dim settings As Map = Utility.ReadSettings
settings.Put("ROOT_URL", Main.ROOT_URL)
settings.Put("ROOT_PATH", Main.ROOT_PATH)
Dim strMain As String = Utility.ReadTextFile("main.html")
Dim strView As String = Utility.ReadTextFile("password.html")
strMain = Utility.BuildView(strMain, strView)
strMain = Utility.BuildHtml(strMain, settings)
Utility.ReturnHTML(strMain, Response)
Return
End If
Dim ActionList As List
ActionList.Initialize2(Array As String("change", "reset", "confirmreset"))
If ActionList.IndexOf(elements(Main.ELEMENT_ACTION)) > -1 Then
OpenConnection
End If
Select elements(Main.ELEMENT_ACTION)
Case "change"
ChangePassword
Case "reset"
ResetPassword
Case "confirmreset"
If elements.Length < Main.MAX_ELEMENTS Then Return
ConfirmReset(elements(Main.ELEMENT_ID))
Case Else
Response.SendError(500, "Unknown action")
Return
End Select
If ActionList.IndexOf(elements(Main.ELEMENT_ACTION)) > -1 Then
CloseConnection
End If
End Sub
Sub RequestData As Map
Try
Dim data As Map
Dim ins As InputStream = Request.InputStream
Dim tr As TextReader
tr.Initialize(ins)
Dim json As JSONParser
json.Initialize(tr.ReadAll)
data = json.NextObject
Catch
LogDebug("[Password/RequestData] " & LastException)
End Try
Return data
End Sub
Sub OpenConnection
Try
Dim config As Map = Utility.ReadConfig
pool.Initialize(config.Get("DriverClass"), _
config.Get("JdbcUrl"), _
config.Get("User"), _
config.Get("Password"))
Dim jo As JavaObject = pool
Dim MaxPoolSize As Int = config.Get("MaxPoolSize")
jo.RunMethod("setMaxPoolSize", Array(MaxPoolSize))
Catch
LogDebug(LastException)
End Try
End Sub
Sub CloseConnection
If pool.IsInitialized Then pool.ClosePool
End Sub
Sub WriteErrorLog(Module As String, Message As String)
Dim con As SQL = pool.GetConnection
Try
Dim strSQL As String = $"INSERT INTO tbl_error (error_text) SELECT ?"$
con.ExecNonQuery2(strSQL, Array As String("[" & Module & "]" & Message))
Catch
LogDebug("[WriteErrorLog] " & LastException)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub WriteUserLog(log_view As String, log_type As String, log_text As String, Log_User As String)
Dim con As SQL = pool.GetConnection
Try
Dim strSQL As String = $"INSERT INTO tbl_users_log
(log_view,
log_type,
log_text,
log_user)
SELECT ?, ?, ?, ?"$
con.ExecNonQuery2(strSQL, Array As String(log_view, log_type, log_text, Log_User))
Catch
Dim msg_text As String = "[Exception] " & LastException
WriteErrorLog("WriteUserLog", msg_text)
Utility.ReturnError("Error-Execute-Query", Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub ChangePassword
Dim con As SQL = pool.GetConnection
Dim msg_text As String
Try
Dim Map1 As Map = RequestData
If Map1 = Null Or Map1.IsInitialized = False Then
msg_text = "[Null Value]"
WriteUserLog("password/change", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
Dim user_email As String = Map1.Get("eml")
Dim old_password As String = Map1.Get("old")
Dim new_password As String = Map1.Get("new")
If user_email = "" Or old_password = "" Or new_password = "" Then
msg_text = "[Value Not Set]"
WriteUserLog("password/change", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
If old_password = new_password Then
msg_text = "[Same Password]"
WriteUserLog("password/change", "fail", msg_text, 0)
Utility.ReturnError("Error-Same-Value", Response)
con.Close
Return
End If
Dim strSQL As String
strSQL = $"SELECT
user_id AS `result`,
'success' AS `message`,
user_name,
user_email,
ifnull(user_location, '') AS user_location,
ifnull(user_api_key, '') AS user_api_key,
user_activation_flag
FROM tbl_users
WHERE user_email = ?
AND user_hash = md5(concat(?, user_salt))"$
Dim result As ResultSet = con.ExecQuery2(strSQL, Array As String(user_email, old_password))
If result.NextRow Then
Dim salt As String = Utility.MD5(Rnd(100001, 999999))
Dim hash As String = Utility.MD5(new_password & salt)
Dim key As String = Utility.SHA1(hash)
' Update User Password
strSQL = $"UPDATE tbl_users SET
user_salt = ?,
user_hash = ?,
user_api_key = ?,
user_token = NULL,
modified_at = now()
WHERE user_email = ?
AND user_hash = MD5(concat(?, user_salt))"$
con.ExecNonQuery2(strSQL, Array As String(salt, hash, key, user_email, old_password))
WriteUserLog("password/change", "success", msg_text, result.GetInt("result"))
Utility.ReturnSuccess("success", Response)
' Send email
SendEmail(result.GetString("user_name"), result.GetString("user_email"), "change", "null", "null")
Else
msg_text = "[Not Found] " & user_email
WriteUserLog("password/change", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Result", Response)
End If
Catch
msg_text = "[Exception] " & LastException
WriteErrorLog("password/change", msg_text)
Utility.ReturnError("Error-Execute-Query", Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub ResetPassword
Dim con As SQL = pool.GetConnection
Dim msg_text As String
Dim strSQL As String
Try
Dim Map1 As Map = RequestData
If Map1 = Null Or Map1.IsInitialized = False Then
msg_text = "[Null Value]"
WriteUserLog("password/reset", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
Dim user_email As String = Map1.Get("eml")
If user_email = "" Then
msg_text = "[Email Not Set]"
WriteUserLog("password/reset", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Value", Response)
con.Close
Return
End If
strSQL = $"SELECT
user_id AS `result`,
'success' AS `message`,
user_email,
user_name
FROM tbl_users
WHERE user_email = ?"$
Dim result As ResultSet = con.ExecQuery2(strSQL, Array As String(user_email))
If result.NextRow Then
Dim code As String = Utility.MD5(Rnd(100001, 999999))
' Update User activation code
strSQL = $"UPDATE tbl_users SET
user_activation_code = ?,
modified_at = now()
WHERE user_email = ?"$
con.ExecNonQuery2(strSQL, Array As String(code, user_email))
WriteUserLog("password/reset", "success", msg_text, result.GetInt("result"))
Utility.ReturnSuccess("success", Response)
' Send email
SendEmail(result.GetString("user_name"), result.GetString("user_email"), "reset", code, "null")
Else
msg_text = "[Not Found] " & user_email
WriteUserLog("password/reset", "fail", msg_text, 0)
Utility.ReturnError("Error-No-Result", Response)
End If
Catch
msg_text = "[Exception] " & LastException
WriteErrorLog("password/reset", msg_text)
Utility.ReturnError("Error-Execute-Query", Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub ConfirmReset(code As String)
Dim con As SQL = pool.GetConnection
Dim msg_text As String
Dim strMain As String
Dim strSQL As String
Try
If code = "" Then
strMain = $"<h1>Reset Password</h1>
<p>Invalid reset code!</p>"$
Utility.ReturnHTML(strMain, Response)
con.Close
Return
Else
strSQL = $"SELECT
user_name,
user_email
FROM tbl_users
WHERE user_activation_code = ?"$
Dim result As ResultSet = con.ExecQuery2(strSQL, Array As String(code))
If result.NextRow Then
' You may use other method To generate a more complex password with alphanumeric
Dim salt As String = Utility.MD5(Rnd(100001, 999999))
Dim temp As String = Utility.MD5(Rnd(100001, 999999))
temp = temp.SubString(temp.Length - 8) ' get last 8 letters
Dim hash As String = Utility.MD5(temp & salt)
Dim code As String = Utility.MD5(hash)
strSQL = $"UPDATE tbl_users SET
user_hash = ?,
user_salt = ?,
user_activation_code = ?,
modified_at = now()
WHERE user_email = ?"$
con.ExecNonQuery2(strSQL, Array As String(hash, salt, code, result.GetString("user_email")))
' Send email
SendEmail(result.GetString("user_name"), result.GetString("user_email"), "confirmreset", "null", temp)
Else
msg_text = "[Not Found] "
WriteUserLog("password/confirmreset", "fail", msg_text, 0)
strMain = $"<h1>Reset Password</h1>
<p>Invalid reset code!</p>"$
Utility.ReturnHTML(strMain, Response)
con.Close
Return
End If
End If
Catch
msg_text = "[Exception] " & LastException
WriteErrorLog("password/confirmreset", msg_text)
Utility.ReturnError("Error-Execute-Query", Response)
End Try
If con <> Null And con.IsInitialized Then con.Close
End Sub
Sub SendEmail(user_name As String, user_email As String, action As String, reset_code As String, temp_password As String)
Dim smtp As SMTP
Dim strMain As String
Try
Dim settings As Map = Utility.ReadSettings
Dim APP_TRADEMARK As String = settings.Get("APP_TRADEMARK")
Dim SMTP_USERNAME As String = settings.Get("SMTP_USERNAME")
Dim SMTP_PASSWORD As String = settings.Get("SMTP_PASSWORD")
Dim SMTP_SERVER As String = settings.Get("SMTP_SERVER")
Dim SMTP_USESSL As String = settings.Get("SMTP_USESSL")
Dim SMTP_PORT As Int = settings.Get("SMTP_PORT")
'Dim HTML_BODY As String = settings.Get("HTML_BODY")
Dim EmailSubject As String
Dim EmailBody As String
Select Case action
Case "change"
EmailSubject = "Your password has been changed"
EmailBody = $"Hi ${user_name},<br />
We have noticed that you have changed your password recently.<br />
<br />
If this action is not initiated by you, please contact us immediately.<br />
Otherwise, please ignore this email.<br />
<br />
Regards,<br />
<em>${APP_TRADEMARK}</em>"$
Case "reset"
EmailSubject = "Request to reset your password"
EmailBody = $"Hi ${user_name},<br />
We have received a request from you to reset your password.<br />
<br />
If this action is not initiated by you, please contact us immediately.<br />
Otherwise, click the following link to confirm:<br />
<br />
<a href="${Main.ROOT_URL}/password/confirmreset/${reset_code}" id="reset-link" title="reset" target="_blank">${Main.ROOT_URL}/password/confirmreset/${reset_code}</a><br />
<br />
If the link is not working, please copy the url to your browser.<br />
If you have changed your mind, just ignore this email.<br />
<br />
Regards,<br />
<em>${APP_TRADEMARK}</em>"$
Case "confirmreset"
EmailSubject = "Your password has been reset"
EmailBody = $"Hi ${user_name},<br />
Your password has been reset.<br />
Please use the following temporary password to log in.<br />
Password: ${temp_password}<br />
<br />
Once you are able to log in, please change to a new password.<br />
<br />
Regards,<br />
<em>${APP_TRADEMARK}</em>"$
strMain = $"<h1>Confirm Reset Password</h1>
<p>Password reset successfully.<br/>Please check your email for temporary password.</p>"$
Utility.ReturnHTML(strMain, Response)
Case Else
strMain = $"<h1>Send Email</h1>
<p>Unrecognized action!</p>"$
Utility.ReturnHTML(strMain, Response)
Return
End Select
smtp.Initialize(SMTP_SERVER, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD, "SMTP")
If SMTP_USESSL.ToUpperCase = "TRUE" Then smtp.UseSSL = True Else smtp.UseSSL = False
smtp.Sender = SMTP_USERNAME
smtp.To.Add(user_email)
smtp.AuthMethod = smtp.AUTH_LOGIN
'If HTML_BODY.ToUpperCase = "TRUE" Then smtp.HtmlBody = True Else smtp.HtmlBody = False
smtp.HtmlBody = True
smtp.Subject = EmailSubject
smtp.Body = EmailBody
LogDebug(smtp.body)
LogDebug("Sending email...")
'Dim sm As Object = smtp.Send
Wait For (smtp.Send) SMTP_MessageSent (Success As Boolean)
If Success Then
LogDebug("Message sent successfully")
Else
LogDebug("Error sending message")
LogDebug(LastException)
End If
Catch
LogDebug(LastException)
Utility.ReturnError("Error-Send-Email", Response)
End Try
End Sub[/CODE]