Collect distinct visitor IP addresses
This commit is contained in:
parent
382c6df96c
commit
ff2eb285eb
|
@ -46,13 +46,20 @@ func LoginRequired(handler http.Handler) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ping LastLoginAt for long lived sessions, but not if impersonated.
|
// Ping LastLoginAt for long lived sessions, but not if impersonated.
|
||||||
|
var pingLastLoginAt bool
|
||||||
if time.Since(user.LastLoginAt) > config.LastLoginAtCooldown && !session.Impersonated(r) {
|
if time.Since(user.LastLoginAt) > config.LastLoginAtCooldown && !session.Impersonated(r) {
|
||||||
user.LastLoginAt = time.Now()
|
user.LastLoginAt = time.Now()
|
||||||
|
pingLastLoginAt = true
|
||||||
if err := user.Save(); err != nil {
|
if err := user.Save(); err != nil {
|
||||||
log.Error("LoginRequired: couldn't refresh LastLoginAt for user %s: %s", user.Username, err)
|
log.Error("LoginRequired: couldn't refresh LastLoginAt for user %s: %s", user.Username, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log the last visit of their current IP address.
|
||||||
|
if err := models.PingIPAddress(r, user, pingLastLoginAt); err != nil {
|
||||||
|
log.Error("LoginRequired: couldn't ping user %s IP address: %s", user.Username, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Ask the user for their birthdate?
|
// Ask the user for their birthdate?
|
||||||
if AgeGate(user, w, r) {
|
if AgeGate(user, w, r) {
|
||||||
return
|
return
|
||||||
|
@ -115,6 +122,11 @@ func CertRequired(handler http.Handler) http.Handler {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log the last visit of their current IP address.
|
||||||
|
if err := models.PingIPAddress(r, currentUser, false); err != nil {
|
||||||
|
log.Error("CertRequired: couldn't ping user %s IP address: %s", currentUser.Username, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Are they banned?
|
// Are they banned?
|
||||||
if currentUser.Status == models.UserStatusBanned {
|
if currentUser.Status == models.UserStatusBanned {
|
||||||
session.LogoutUser(w, r)
|
session.LogoutUser(w, r)
|
||||||
|
|
|
@ -54,6 +54,7 @@ func DeleteUser(user *models.User) error {
|
||||||
{"Profile Fields", DeleteProfile},
|
{"Profile Fields", DeleteProfile},
|
||||||
{"User Notes", DeleteUserNotes},
|
{"User Notes", DeleteUserNotes},
|
||||||
{"Change Logs", DeleteChangeLogs},
|
{"Change Logs", DeleteChangeLogs},
|
||||||
|
{"IP Addresses", DeleteIPAddresses},
|
||||||
}
|
}
|
||||||
for _, item := range todo {
|
for _, item := range todo {
|
||||||
if err := item.Fn(user.ID); err != nil {
|
if err := item.Fn(user.ID); err != nil {
|
||||||
|
@ -350,3 +351,13 @@ func DeleteChangeLogs(userID uint64) error {
|
||||||
).Delete(&models.ChangeLog{})
|
).Delete(&models.ChangeLog{})
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteIPAddresses scrubs data for deleting a user.
|
||||||
|
func DeleteIPAddresses(userID uint64) error {
|
||||||
|
log.Error("DeleteUser: DeleteIPAddresses(%d)", userID)
|
||||||
|
result := models.DB.Where(
|
||||||
|
"user_id = ?",
|
||||||
|
userID,
|
||||||
|
).Delete(&models.IPAddress{})
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ func ExportModels(zw *zip.Writer, user *models.User) error {
|
||||||
{"UserNote", ExportUserNoteTable},
|
{"UserNote", ExportUserNoteTable},
|
||||||
{"ChangeLog", ExportChangeLogTable},
|
{"ChangeLog", ExportChangeLogTable},
|
||||||
{"TwoFactor", ExportTwoFactorTable},
|
{"TwoFactor", ExportTwoFactorTable},
|
||||||
|
{"IPAddress", ExportIPAddressTable},
|
||||||
}
|
}
|
||||||
for _, item := range todo {
|
for _, item := range todo {
|
||||||
log.Info("Exporting data model: %s", item.Step)
|
log.Info("Exporting data model: %s", item.Step)
|
||||||
|
@ -428,3 +429,18 @@ func ExportTwoFactorTable(zw *zip.Writer, user *models.User) error {
|
||||||
|
|
||||||
return ZipJson(zw, "two_factor.json", items)
|
return ZipJson(zw, "two_factor.json", items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExportIPAddressTable(zw *zip.Writer, user *models.User) error {
|
||||||
|
var (
|
||||||
|
items = []*models.IPAddress{}
|
||||||
|
query = models.DB.Model(&models.IPAddress{}).Where(
|
||||||
|
"user_id = ?",
|
||||||
|
user.ID,
|
||||||
|
).Find(&items)
|
||||||
|
)
|
||||||
|
if query.Error != nil {
|
||||||
|
return query.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return ZipJson(zw, "ip_addresses.json", items)
|
||||||
|
}
|
||||||
|
|
74
pkg/models/ip_addresses.go
Normal file
74
pkg/models/ip_addresses.go
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.nonshy.com/nonshy/website/pkg/log"
|
||||||
|
"code.nonshy.com/nonshy/website/pkg/utility"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IPAddress table to log which networks users have logged in from.
|
||||||
|
type IPAddress struct {
|
||||||
|
ID uint64 `gorm:"primaryKey"`
|
||||||
|
UserID uint64 `gorm:"index"`
|
||||||
|
IPAddress string `gorm:"index"`
|
||||||
|
NumberVisits uint64 // count of times their LastLoginAt pinged from this address
|
||||||
|
CreatedAt time.Time // first time seen
|
||||||
|
UpdatedAt time.Time // last time seen
|
||||||
|
}
|
||||||
|
|
||||||
|
// PingIPAddress logs or upserts the user's current IP address into the IPAddress table.
|
||||||
|
func PingIPAddress(r *http.Request, user *User, incrementVisit bool) error {
|
||||||
|
var (
|
||||||
|
addr = utility.IPAddress(r)
|
||||||
|
ip *IPAddress
|
||||||
|
)
|
||||||
|
|
||||||
|
// Have we seen it before?
|
||||||
|
ip, err := LoadUserIPAddress(user, addr)
|
||||||
|
if err != nil {
|
||||||
|
// Insert it.
|
||||||
|
log.Debug("User %s IP %s seen for the first time", user.Username, addr)
|
||||||
|
ip = &IPAddress{
|
||||||
|
UserID: user.ID,
|
||||||
|
IPAddress: addr,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
result := DB.Create(ip)
|
||||||
|
if result.Error != nil {
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we refreshing the NumberVisits count? Note: this happens each
|
||||||
|
// time the main website will refresh the user LastLoginAt.
|
||||||
|
if incrementVisit || ip.NumberVisits == 0 {
|
||||||
|
ip.NumberVisits++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping the update.
|
||||||
|
ip.UpdatedAt = time.Now()
|
||||||
|
return ip.Save()
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadUserIPAddress(user *User, ipAddr string) (*IPAddress, error) {
|
||||||
|
var ip = &IPAddress{}
|
||||||
|
var result = DB.Model(&IPAddress{}).Where(
|
||||||
|
"user_id = ? AND ip_address = ?",
|
||||||
|
user.ID, ipAddr,
|
||||||
|
).First(&ip)
|
||||||
|
return ip, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save photo.
|
||||||
|
func (ip *IPAddress) Save() error {
|
||||||
|
result := DB.Save(ip)
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the DB entry.
|
||||||
|
func (ip *IPAddress) Delete() error {
|
||||||
|
return DB.Delete(ip).Error
|
||||||
|
}
|
|
@ -32,4 +32,5 @@ func AutoMigrate() {
|
||||||
DB.AutoMigrate(&UserNote{})
|
DB.AutoMigrate(&UserNote{})
|
||||||
DB.AutoMigrate(&TwoFactor{})
|
DB.AutoMigrate(&TwoFactor{})
|
||||||
DB.AutoMigrate(&ChangeLog{})
|
DB.AutoMigrate(&ChangeLog{})
|
||||||
|
DB.AutoMigrate(&IPAddress{})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user