github.com/readium/readium-lcp-server@v0.0.0-20240101192032-6e95190e99f1/license_statuses/license_statuses.go (about) 1 // Copyright 2020 Readium Foundation. All rights reserved. 2 // Use of this source code is governed by a BSD-style license 3 // that can be found in the LICENSE file exposed on Github (readium) in the project repository. 4 5 package licensestatuses 6 7 import ( 8 "database/sql" 9 "errors" 10 "log" 11 "time" 12 13 "github.com/readium/readium-lcp-server/config" 14 "github.com/readium/readium-lcp-server/status" 15 ) 16 17 // ErrNotFound is license status not found 18 var ErrNotFound = errors.New("license Status not found") 19 20 // LicenseStatuses is an interface 21 type LicenseStatuses interface { 22 GetByID(id int) (*LicenseStatus, error) 23 Add(ls LicenseStatus) error 24 List(deviceLimit int64, limit int64, offset int64) func() (LicenseStatus, error) 25 GetByLicenseID(id string) (*LicenseStatus, error) 26 Update(ls LicenseStatus) error 27 } 28 29 type dbLicenseStatuses struct { 30 db *sql.DB 31 dbGet *sql.Stmt 32 dbList *sql.Stmt 33 dbGetByLicenseID *sql.Stmt 34 } 35 36 // Get retrieves a license status by id 37 func (i dbLicenseStatuses) GetByID(id int) (*LicenseStatus, error) { 38 var statusDB int64 39 ls := LicenseStatus{} 40 41 var potentialRightsEnd *time.Time 42 var licenseUpdate *time.Time 43 var statusUpdate *time.Time 44 45 row := i.dbGet.QueryRow(id) 46 err := row.Scan(&ls.ID, &statusDB, &licenseUpdate, &statusUpdate, &ls.DeviceCount, &potentialRightsEnd, &ls.LicenseRef, &ls.CurrentEndLicense) 47 48 if err == nil { 49 status.GetStatus(statusDB, &ls.Status) 50 51 ls.Updated = new(Updated) 52 53 if (potentialRightsEnd != nil) && (!(*potentialRightsEnd).IsZero()) { 54 ls.PotentialRights = new(PotentialRights) 55 ls.PotentialRights.End = potentialRightsEnd 56 } 57 58 ls.Updated.Status = statusUpdate 59 ls.Updated.License = licenseUpdate 60 // fix an issue with clients which test that the date of last update of the license 61 // is after the date of creation of the X509 certificate. 62 // Associated with a fix to the license server. 63 if config.Config.LcpServer.CertDate != "" { 64 certDate, err := time.Parse("2006-01-02", config.Config.LcpServer.CertDate) 65 if err == nil { 66 if ls.Updated.License == nil || ls.Updated.License.Before(certDate) { 67 ls.Updated.License = &certDate 68 } 69 } 70 } 71 } else { 72 if err == sql.ErrNoRows { 73 return nil, ErrNotFound 74 } 75 } 76 77 return &ls, err 78 } 79 80 // Add adds license status to database 81 func (i dbLicenseStatuses) Add(ls LicenseStatus) error { 82 83 statusDB, err := status.SetStatus(ls.Status) 84 if err == nil { 85 var end *time.Time 86 end = nil 87 if ls.PotentialRights != nil && ls.PotentialRights.End != nil && !(*ls.PotentialRights.End).IsZero() { 88 end = ls.PotentialRights.End 89 } 90 _, err = i.db.Exec(`INSERT INTO license_status 91 (status, license_updated, status_updated, device_count, potential_rights_end, license_ref, rights_end) 92 VALUES (?, ?, ?, ?, ?, ?, ?)`, 93 statusDB, ls.Updated.License, ls.Updated.Status, ls.DeviceCount, end, ls.LicenseRef, ls.CurrentEndLicense) 94 } 95 96 return err 97 } 98 99 // List gets license statuses which have devices count more than devices limit 100 // input parameters: limit - how many license statuses need to get, offset - from what position need to start 101 func (i dbLicenseStatuses) List(deviceLimit int64, limit int64, offset int64) func() (LicenseStatus, error) { 102 103 var rows *sql.Rows 104 var err error 105 driver, _ := config.GetDatabase(config.Config.LsdServer.Database) 106 if driver == "mssql" { 107 rows, err = i.dbList.Query(deviceLimit, offset, limit) 108 } else { 109 rows, err = i.dbList.Query(deviceLimit, limit, offset) 110 } 111 if err != nil { 112 return func() (LicenseStatus, error) { return LicenseStatus{}, err } 113 } 114 115 return func() (LicenseStatus, error) { 116 var statusDB int64 117 var err error 118 119 ls := LicenseStatus{} 120 ls.Updated = new(Updated) 121 if rows.Next() { 122 err = rows.Scan(&ls.ID, &statusDB, &ls.Updated.License, &ls.Updated.Status, &ls.DeviceCount, &ls.LicenseRef) 123 124 if err == nil { 125 status.GetStatus(statusDB, &ls.Status) 126 } 127 } else { 128 rows.Close() 129 err = ErrNotFound 130 } 131 return ls, err 132 } 133 } 134 135 // GetByLicenseID gets license status by license id (uuid) 136 func (i dbLicenseStatuses) GetByLicenseID(licenseID string) (*LicenseStatus, error) { 137 var statusDB int64 138 ls := LicenseStatus{} 139 140 var potentialRightsEnd *time.Time 141 var licenseUpdate *time.Time 142 var statusUpdate *time.Time 143 144 row := i.dbGetByLicenseID.QueryRow(licenseID) 145 err := row.Scan(&ls.ID, &statusDB, &licenseUpdate, &statusUpdate, &ls.DeviceCount, &potentialRightsEnd, &ls.LicenseRef, &ls.CurrentEndLicense) 146 147 if err == nil { 148 status.GetStatus(statusDB, &ls.Status) 149 150 ls.Updated = new(Updated) 151 152 if (potentialRightsEnd != nil) && (!(*potentialRightsEnd).IsZero()) { 153 ls.PotentialRights = new(PotentialRights) 154 ls.PotentialRights.End = potentialRightsEnd 155 } 156 157 ls.Updated.Status = statusUpdate 158 ls.Updated.License = licenseUpdate 159 // fix an issue with clients which test that the date of last update of the license 160 // is after the date of creation of the X509 certificate. 161 // Associated with a fix to the license server. 162 if config.Config.LcpServer.CertDate != "" { 163 certDate, err := time.Parse("2006-01-02", config.Config.LcpServer.CertDate) 164 if err == nil { 165 if ls.Updated.License == nil || ls.Updated.License.Before(certDate) { 166 ls.Updated.License = &certDate 167 } 168 } 169 } 170 } else { 171 if err == sql.ErrNoRows { 172 return nil, ErrNotFound 173 } 174 } 175 176 return &ls, err 177 } 178 179 // Update updates a license status 180 func (i dbLicenseStatuses) Update(ls LicenseStatus) error { 181 182 statusInt, err := status.SetStatus(ls.Status) 183 if err != nil { 184 return err 185 } 186 187 var potentialRightsEnd *time.Time 188 189 if ls.PotentialRights != nil && ls.PotentialRights.End != nil && !(*ls.PotentialRights.End).IsZero() { 190 potentialRightsEnd = ls.PotentialRights.End 191 } 192 193 var result sql.Result 194 result, err = i.db.Exec(`UPDATE license_status SET status=?, license_updated=?, status_updated=?, 195 device_count=?,potential_rights_end=?, rights_end=? WHERE id=?`, 196 statusInt, ls.Updated.License, ls.Updated.Status, ls.DeviceCount, potentialRightsEnd, ls.CurrentEndLicense, ls.ID) 197 198 if err == nil { 199 if r, _ := result.RowsAffected(); r == 0 { 200 return ErrNotFound 201 } 202 } 203 return err 204 } 205 206 // Open defines scripts for queries & create table license_status if it does not exist 207 func Open(db *sql.DB) (l LicenseStatuses, err error) { 208 209 driver, _ := config.GetDatabase(config.Config.LsdServer.Database) 210 211 // if sqlite, create the license table if it does not exist 212 if driver == "sqlite3" { 213 _, err = db.Exec(tableDef) 214 if err != nil { 215 log.Println("Error creating license_status table") 216 return 217 } 218 } 219 220 dbGet, err := db.Prepare("SELECT * FROM license_status WHERE id = ?") 221 if err != nil { 222 return 223 } 224 225 var dbList *sql.Stmt 226 if driver == "mssql" { 227 dbList, err = db.Prepare(`SELECT id, status, license_updated, status_updated, device_count, license_ref FROM license_status WHERE device_count >= ? 228 ORDER BY id DESC OFFSET ? ROWS FETCH NEXT ? ROWS ONLY`) 229 } else { 230 dbList, err = db.Prepare(`SELECT id, status, license_updated, status_updated, device_count, license_ref FROM license_status WHERE device_count >= ? 231 ORDER BY id DESC LIMIT ? OFFSET ?`) 232 233 } 234 if err != nil { 235 return 236 } 237 238 dbGetByLicenseID, err := db.Prepare("SELECT * FROM license_status where license_ref = ?") 239 if err != nil { 240 return 241 } 242 243 l = dbLicenseStatuses{db, dbGet, dbList, dbGetByLicenseID} 244 return 245 } 246 247 const tableDef = "CREATE TABLE IF NOT EXISTS license_status (" + 248 "id INTEGER PRIMARY KEY," + 249 "status int(11) NOT NULL," + 250 "license_updated datetime NOT NULL," + 251 "status_updated datetime NOT NULL," + 252 "device_count int(11) DEFAULT NULL," + 253 "potential_rights_end datetime DEFAULT NULL," + 254 "license_ref varchar(255) NOT NULL," + 255 "rights_end datetime DEFAULT NULL " + 256 ");" + 257 "CREATE INDEX IF NOT EXISTS license_ref_index on license_status (license_ref);"