github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/store/sqlstore/integrity.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package sqlstore 5 6 import ( 7 sq "github.com/Masterminds/squirrel" 8 9 "github.com/mattermost/mattermost-server/v5/mlog" 10 "github.com/mattermost/mattermost-server/v5/model" 11 ) 12 13 type relationalCheckConfig struct { 14 parentName string 15 parentIdAttr string 16 childName string 17 childIdAttr string 18 canParentIdBeEmpty bool 19 sortRecords bool 20 filter interface{} 21 } 22 23 func getOrphanedRecords(ss *SqlStore, cfg relationalCheckConfig) ([]model.OrphanedRecord, error) { 24 var records []model.OrphanedRecord 25 26 sub := ss.getQueryBuilder(). 27 Select("TRUE"). 28 From(cfg.parentName + " AS PT"). 29 Prefix("NOT EXISTS ("). 30 Suffix(")"). 31 Where("PT.id = CT." + cfg.parentIdAttr) 32 33 main := ss.getQueryBuilder(). 34 Select(). 35 Column("CT." + cfg.parentIdAttr + " AS ParentId"). 36 From(cfg.childName + " AS CT"). 37 Where(sub) 38 39 if cfg.childIdAttr != "" { 40 main = main.Column("CT." + cfg.childIdAttr + " AS ChildId") 41 } 42 43 if cfg.canParentIdBeEmpty { 44 main = main.Where(sq.NotEq{"CT." + cfg.parentIdAttr: ""}) 45 } 46 47 if cfg.filter != nil { 48 main = main.Where(cfg.filter) 49 } 50 51 if cfg.sortRecords { 52 main = main.OrderBy("CT." + cfg.parentIdAttr) 53 } 54 55 query, args, _ := main.ToSql() 56 57 _, err := ss.GetMaster().Select(&records, query, args...) 58 59 return records, err 60 } 61 62 func checkParentChildIntegrity(ss *SqlStore, config relationalCheckConfig) model.IntegrityCheckResult { 63 var result model.IntegrityCheckResult 64 var data model.RelationalIntegrityCheckData 65 66 config.sortRecords = true 67 data.Records, result.Err = getOrphanedRecords(ss, config) 68 if result.Err != nil { 69 mlog.Error("Error while getting orphaned records", mlog.Err(result.Err)) 70 return result 71 } 72 data.ParentName = config.parentName 73 data.ChildName = config.childName 74 data.ParentIdAttr = config.parentIdAttr 75 data.ChildIdAttr = config.childIdAttr 76 result.Data = data 77 78 return result 79 } 80 81 func checkChannelsCommandWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult { 82 return checkParentChildIntegrity(ss, relationalCheckConfig{ 83 parentName: "Channels", 84 parentIdAttr: "ChannelId", 85 childName: "CommandWebhooks", 86 childIdAttr: "Id", 87 }) 88 } 89 90 func checkChannelsChannelMemberHistoryIntegrity(ss *SqlStore) model.IntegrityCheckResult { 91 return checkParentChildIntegrity(ss, relationalCheckConfig{ 92 parentName: "Channels", 93 parentIdAttr: "ChannelId", 94 childName: "ChannelMemberHistory", 95 childIdAttr: "", 96 }) 97 } 98 99 func checkChannelsChannelMembersIntegrity(ss *SqlStore) model.IntegrityCheckResult { 100 return checkParentChildIntegrity(ss, relationalCheckConfig{ 101 parentName: "Channels", 102 parentIdAttr: "ChannelId", 103 childName: "ChannelMembers", 104 childIdAttr: "", 105 }) 106 } 107 108 func checkChannelsIncomingWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult { 109 return checkParentChildIntegrity(ss, relationalCheckConfig{ 110 parentName: "Channels", 111 parentIdAttr: "ChannelId", 112 childName: "IncomingWebhooks", 113 childIdAttr: "Id", 114 }) 115 } 116 117 func checkChannelsOutgoingWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult { 118 return checkParentChildIntegrity(ss, relationalCheckConfig{ 119 parentName: "Channels", 120 parentIdAttr: "ChannelId", 121 childName: "OutgoingWebhooks", 122 childIdAttr: "Id", 123 }) 124 } 125 126 func checkChannelsPostsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 127 return checkParentChildIntegrity(ss, relationalCheckConfig{ 128 parentName: "Channels", 129 parentIdAttr: "ChannelId", 130 childName: "Posts", 131 childIdAttr: "Id", 132 }) 133 } 134 135 func checkCommandsCommandWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult { 136 return checkParentChildIntegrity(ss, relationalCheckConfig{ 137 parentName: "Commands", 138 parentIdAttr: "CommandId", 139 childName: "CommandWebhooks", 140 childIdAttr: "Id", 141 }) 142 } 143 144 func checkPostsFileInfoIntegrity(ss *SqlStore) model.IntegrityCheckResult { 145 return checkParentChildIntegrity(ss, relationalCheckConfig{ 146 parentName: "Posts", 147 parentIdAttr: "PostId", 148 childName: "FileInfo", 149 childIdAttr: "Id", 150 }) 151 } 152 153 func checkPostsPostsParentIdIntegrity(ss *SqlStore) model.IntegrityCheckResult { 154 return checkParentChildIntegrity(ss, relationalCheckConfig{ 155 parentName: "Posts", 156 parentIdAttr: "ParentId", 157 childName: "Posts", 158 childIdAttr: "Id", 159 canParentIdBeEmpty: true, 160 }) 161 } 162 163 func checkPostsPostsRootIdIntegrity(ss *SqlStore) model.IntegrityCheckResult { 164 return checkParentChildIntegrity(ss, relationalCheckConfig{ 165 parentName: "Posts", 166 parentIdAttr: "RootId", 167 childName: "Posts", 168 childIdAttr: "Id", 169 canParentIdBeEmpty: true, 170 }) 171 } 172 173 func checkPostsReactionsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 174 return checkParentChildIntegrity(ss, relationalCheckConfig{ 175 parentName: "Posts", 176 parentIdAttr: "PostId", 177 childName: "Reactions", 178 childIdAttr: "", 179 }) 180 } 181 182 func checkSchemesChannelsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 183 return checkParentChildIntegrity(ss, relationalCheckConfig{ 184 parentName: "Schemes", 185 parentIdAttr: "SchemeId", 186 childName: "Channels", 187 childIdAttr: "Id", 188 canParentIdBeEmpty: true, 189 }) 190 } 191 192 func checkSchemesTeamsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 193 return checkParentChildIntegrity(ss, relationalCheckConfig{ 194 parentName: "Schemes", 195 parentIdAttr: "SchemeId", 196 childName: "Teams", 197 childIdAttr: "Id", 198 canParentIdBeEmpty: true, 199 }) 200 } 201 202 func checkSessionsAuditsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 203 return checkParentChildIntegrity(ss, relationalCheckConfig{ 204 parentName: "Sessions", 205 parentIdAttr: "SessionId", 206 childName: "Audits", 207 childIdAttr: "Id", 208 canParentIdBeEmpty: true, 209 }) 210 } 211 212 func checkTeamsChannelsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 213 res1 := checkParentChildIntegrity(ss, relationalCheckConfig{ 214 parentName: "Teams", 215 parentIdAttr: "TeamId", 216 childName: "Channels", 217 childIdAttr: "Id", 218 filter: sq.NotEq{"CT.Type": []string{model.CHANNEL_DIRECT, model.CHANNEL_GROUP}}, 219 }) 220 res2 := checkParentChildIntegrity(ss, relationalCheckConfig{ 221 parentName: "Teams", 222 parentIdAttr: "TeamId", 223 childName: "Channels", 224 childIdAttr: "Id", 225 canParentIdBeEmpty: true, 226 filter: sq.Eq{"CT.Type": []string{model.CHANNEL_DIRECT, model.CHANNEL_GROUP}}, 227 }) 228 data1 := res1.Data.(model.RelationalIntegrityCheckData) 229 data2 := res2.Data.(model.RelationalIntegrityCheckData) 230 data1.Records = append(data1.Records, data2.Records...) 231 res1.Data = data1 232 return res1 233 } 234 235 func checkTeamsCommandsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 236 return checkParentChildIntegrity(ss, relationalCheckConfig{ 237 parentName: "Teams", 238 parentIdAttr: "TeamId", 239 childName: "Commands", 240 childIdAttr: "Id", 241 }) 242 } 243 244 func checkTeamsIncomingWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult { 245 return checkParentChildIntegrity(ss, relationalCheckConfig{ 246 parentName: "Teams", 247 parentIdAttr: "TeamId", 248 childName: "IncomingWebhooks", 249 childIdAttr: "Id", 250 }) 251 } 252 253 func checkTeamsOutgoingWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult { 254 return checkParentChildIntegrity(ss, relationalCheckConfig{ 255 parentName: "Teams", 256 parentIdAttr: "TeamId", 257 childName: "OutgoingWebhooks", 258 childIdAttr: "Id", 259 }) 260 } 261 262 func checkTeamsTeamMembersIntegrity(ss *SqlStore) model.IntegrityCheckResult { 263 return checkParentChildIntegrity(ss, relationalCheckConfig{ 264 parentName: "Teams", 265 parentIdAttr: "TeamId", 266 childName: "TeamMembers", 267 childIdAttr: "", 268 }) 269 } 270 271 func checkUsersAuditsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 272 return checkParentChildIntegrity(ss, relationalCheckConfig{ 273 parentName: "Users", 274 parentIdAttr: "UserId", 275 childName: "Audits", 276 childIdAttr: "Id", 277 canParentIdBeEmpty: true, 278 }) 279 } 280 281 func checkUsersCommandWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult { 282 return checkParentChildIntegrity(ss, relationalCheckConfig{ 283 parentName: "Users", 284 parentIdAttr: "UserId", 285 childName: "CommandWebhooks", 286 childIdAttr: "Id", 287 }) 288 } 289 290 func checkUsersChannelMemberHistoryIntegrity(ss *SqlStore) model.IntegrityCheckResult { 291 return checkParentChildIntegrity(ss, relationalCheckConfig{ 292 parentName: "Users", 293 parentIdAttr: "UserId", 294 childName: "ChannelMemberHistory", 295 childIdAttr: "", 296 }) 297 } 298 299 func checkUsersChannelMembersIntegrity(ss *SqlStore) model.IntegrityCheckResult { 300 return checkParentChildIntegrity(ss, relationalCheckConfig{ 301 parentName: "Users", 302 parentIdAttr: "UserId", 303 childName: "ChannelMembers", 304 childIdAttr: "", 305 }) 306 } 307 308 func checkUsersChannelsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 309 return checkParentChildIntegrity(ss, relationalCheckConfig{ 310 parentName: "Users", 311 parentIdAttr: "CreatorId", 312 childName: "Channels", 313 childIdAttr: "Id", 314 canParentIdBeEmpty: true, 315 }) 316 } 317 318 func checkUsersCommandsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 319 return checkParentChildIntegrity(ss, relationalCheckConfig{ 320 parentName: "Users", 321 parentIdAttr: "CreatorId", 322 childName: "Commands", 323 childIdAttr: "Id", 324 }) 325 } 326 327 func checkUsersCompliancesIntegrity(ss *SqlStore) model.IntegrityCheckResult { 328 return checkParentChildIntegrity(ss, relationalCheckConfig{ 329 parentName: "Users", 330 parentIdAttr: "UserId", 331 childName: "Compliances", 332 childIdAttr: "Id", 333 }) 334 } 335 336 func checkUsersEmojiIntegrity(ss *SqlStore) model.IntegrityCheckResult { 337 return checkParentChildIntegrity(ss, relationalCheckConfig{ 338 parentName: "Users", 339 parentIdAttr: "CreatorId", 340 childName: "Emoji", 341 childIdAttr: "Id", 342 }) 343 } 344 345 func checkUsersFileInfoIntegrity(ss *SqlStore) model.IntegrityCheckResult { 346 return checkParentChildIntegrity(ss, relationalCheckConfig{ 347 parentName: "Users", 348 parentIdAttr: "CreatorId", 349 childName: "FileInfo", 350 childIdAttr: "Id", 351 }) 352 } 353 354 func checkUsersIncomingWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult { 355 return checkParentChildIntegrity(ss, relationalCheckConfig{ 356 parentName: "Users", 357 parentIdAttr: "UserId", 358 childName: "IncomingWebhooks", 359 childIdAttr: "Id", 360 }) 361 } 362 363 func checkUsersOAuthAccessDataIntegrity(ss *SqlStore) model.IntegrityCheckResult { 364 return checkParentChildIntegrity(ss, relationalCheckConfig{ 365 parentName: "Users", 366 parentIdAttr: "UserId", 367 childName: "OAuthAccessData", 368 childIdAttr: "Token", 369 }) 370 } 371 372 func checkUsersOAuthAppsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 373 return checkParentChildIntegrity(ss, relationalCheckConfig{ 374 parentName: "Users", 375 parentIdAttr: "CreatorId", 376 childName: "OAuthApps", 377 childIdAttr: "Id", 378 }) 379 } 380 381 func checkUsersOAuthAuthDataIntegrity(ss *SqlStore) model.IntegrityCheckResult { 382 return checkParentChildIntegrity(ss, relationalCheckConfig{ 383 parentName: "Users", 384 parentIdAttr: "UserId", 385 childName: "OAuthAuthData", 386 childIdAttr: "Code", 387 }) 388 } 389 390 func checkUsersOutgoingWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult { 391 return checkParentChildIntegrity(ss, relationalCheckConfig{ 392 parentName: "Users", 393 parentIdAttr: "CreatorId", 394 childName: "OutgoingWebhooks", 395 childIdAttr: "Id", 396 }) 397 } 398 399 func checkUsersPostsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 400 return checkParentChildIntegrity(ss, relationalCheckConfig{ 401 parentName: "Users", 402 parentIdAttr: "UserId", 403 childName: "Posts", 404 childIdAttr: "Id", 405 }) 406 } 407 408 func checkUsersPreferencesIntegrity(ss *SqlStore) model.IntegrityCheckResult { 409 return checkParentChildIntegrity(ss, relationalCheckConfig{ 410 parentName: "Users", 411 parentIdAttr: "UserId", 412 childName: "Preferences", 413 childIdAttr: "", 414 }) 415 } 416 417 func checkUsersReactionsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 418 return checkParentChildIntegrity(ss, relationalCheckConfig{ 419 parentName: "Users", 420 parentIdAttr: "UserId", 421 childName: "Reactions", 422 childIdAttr: "", 423 }) 424 } 425 426 func checkUsersSessionsIntegrity(ss *SqlStore) model.IntegrityCheckResult { 427 return checkParentChildIntegrity(ss, relationalCheckConfig{ 428 parentName: "Users", 429 parentIdAttr: "UserId", 430 childName: "Sessions", 431 childIdAttr: "Id", 432 }) 433 } 434 435 func checkUsersStatusIntegrity(ss *SqlStore) model.IntegrityCheckResult { 436 return checkParentChildIntegrity(ss, relationalCheckConfig{ 437 parentName: "Users", 438 parentIdAttr: "UserId", 439 childName: "Status", 440 childIdAttr: "", 441 }) 442 } 443 444 func checkUsersTeamMembersIntegrity(ss *SqlStore) model.IntegrityCheckResult { 445 return checkParentChildIntegrity(ss, relationalCheckConfig{ 446 parentName: "Users", 447 parentIdAttr: "UserId", 448 childName: "TeamMembers", 449 childIdAttr: "", 450 }) 451 } 452 453 func checkUsersUserAccessTokensIntegrity(ss *SqlStore) model.IntegrityCheckResult { 454 return checkParentChildIntegrity(ss, relationalCheckConfig{ 455 parentName: "Users", 456 parentIdAttr: "UserId", 457 childName: "UserAccessTokens", 458 childIdAttr: "Id", 459 }) 460 } 461 462 func checkChannelsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) { 463 results <- checkChannelsCommandWebhooksIntegrity(ss) 464 results <- checkChannelsChannelMemberHistoryIntegrity(ss) 465 results <- checkChannelsChannelMembersIntegrity(ss) 466 results <- checkChannelsIncomingWebhooksIntegrity(ss) 467 results <- checkChannelsOutgoingWebhooksIntegrity(ss) 468 results <- checkChannelsPostsIntegrity(ss) 469 } 470 471 func checkCommandsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) { 472 results <- checkCommandsCommandWebhooksIntegrity(ss) 473 } 474 475 func checkPostsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) { 476 results <- checkPostsFileInfoIntegrity(ss) 477 results <- checkPostsPostsParentIdIntegrity(ss) 478 results <- checkPostsPostsRootIdIntegrity(ss) 479 results <- checkPostsReactionsIntegrity(ss) 480 } 481 482 func checkSchemesIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) { 483 results <- checkSchemesChannelsIntegrity(ss) 484 results <- checkSchemesTeamsIntegrity(ss) 485 } 486 487 func checkSessionsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) { 488 results <- checkSessionsAuditsIntegrity(ss) 489 } 490 491 func checkTeamsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) { 492 results <- checkTeamsChannelsIntegrity(ss) 493 results <- checkTeamsCommandsIntegrity(ss) 494 results <- checkTeamsIncomingWebhooksIntegrity(ss) 495 results <- checkTeamsOutgoingWebhooksIntegrity(ss) 496 results <- checkTeamsTeamMembersIntegrity(ss) 497 } 498 499 func checkUsersIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) { 500 results <- checkUsersAuditsIntegrity(ss) 501 results <- checkUsersCommandWebhooksIntegrity(ss) 502 results <- checkUsersChannelMemberHistoryIntegrity(ss) 503 results <- checkUsersChannelMembersIntegrity(ss) 504 results <- checkUsersChannelsIntegrity(ss) 505 results <- checkUsersCommandsIntegrity(ss) 506 results <- checkUsersCompliancesIntegrity(ss) 507 results <- checkUsersEmojiIntegrity(ss) 508 results <- checkUsersFileInfoIntegrity(ss) 509 results <- checkUsersIncomingWebhooksIntegrity(ss) 510 results <- checkUsersOAuthAccessDataIntegrity(ss) 511 results <- checkUsersOAuthAppsIntegrity(ss) 512 results <- checkUsersOAuthAuthDataIntegrity(ss) 513 results <- checkUsersOutgoingWebhooksIntegrity(ss) 514 results <- checkUsersPostsIntegrity(ss) 515 results <- checkUsersPreferencesIntegrity(ss) 516 results <- checkUsersReactionsIntegrity(ss) 517 results <- checkUsersSessionsIntegrity(ss) 518 results <- checkUsersStatusIntegrity(ss) 519 results <- checkUsersTeamMembersIntegrity(ss) 520 results <- checkUsersUserAccessTokensIntegrity(ss) 521 } 522 523 func CheckRelationalIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) { 524 mlog.Info("Starting relational integrity checks...") 525 checkChannelsIntegrity(ss, results) 526 checkCommandsIntegrity(ss, results) 527 checkPostsIntegrity(ss, results) 528 checkSchemesIntegrity(ss, results) 529 checkSessionsIntegrity(ss, results) 530 checkTeamsIntegrity(ss, results) 531 checkUsersIntegrity(ss, results) 532 mlog.Info("Done with relational integrity checks") 533 close(results) 534 }