You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
5.9 KiB

  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package migrations
  5. import (
  6. "fmt"
  7. "strings"
  8. "code.gitea.io/gitea/modules/log"
  9. "code.gitea.io/gitea/modules/setting"
  10. "xorm.io/xorm"
  11. "xorm.io/xorm/schemas"
  12. )
  13. func setDefaultPasswordToArgon2(x *xorm.Engine) error {
  14. switch {
  15. case setting.Database.UseMySQL:
  16. _, err := x.Exec("ALTER TABLE `user` ALTER passwd_hash_algo SET DEFAULT 'argon2';")
  17. return err
  18. case setting.Database.UsePostgreSQL:
  19. _, err := x.Exec("ALTER TABLE `user` ALTER COLUMN passwd_hash_algo SET DEFAULT 'argon2';")
  20. return err
  21. case setting.Database.UseMSSQL:
  22. // need to find the constraint and drop it, then recreate it.
  23. sess := x.NewSession()
  24. defer sess.Close()
  25. if err := sess.Begin(); err != nil {
  26. return err
  27. }
  28. res, err := sess.QueryString("SELECT [name] FROM sys.default_constraints WHERE parent_object_id=OBJECT_ID(?) AND COL_NAME(parent_object_id, parent_column_id)=?;", "user", "passwd_hash_algo")
  29. if err != nil {
  30. return err
  31. }
  32. if len(res) > 0 {
  33. constraintName := res[0]["name"]
  34. log.Error("Results of select constraint: %s", constraintName)
  35. _, err := sess.Exec("ALTER TABLE [user] DROP CONSTRAINT " + constraintName)
  36. if err != nil {
  37. return err
  38. }
  39. _, err = sess.Exec("ALTER TABLE [user] ADD CONSTRAINT " + constraintName + " DEFAULT 'argon2' FOR passwd_hash_algo")
  40. if err != nil {
  41. return err
  42. }
  43. } else {
  44. _, err := sess.Exec("ALTER TABLE [user] ADD DEFAULT('argon2') FOR passwd_hash_algo")
  45. if err != nil {
  46. return err
  47. }
  48. }
  49. return sess.Commit()
  50. case setting.Database.UseSQLite3:
  51. // drop through
  52. default:
  53. log.Fatal("Unrecognized DB")
  54. }
  55. tables, err := x.DBMetas()
  56. if err != nil {
  57. return err
  58. }
  59. // Now for SQLite we have to recreate the table
  60. var table *schemas.Table
  61. tableName := "user"
  62. for _, table = range tables {
  63. if table.Name == tableName {
  64. break
  65. }
  66. }
  67. if table == nil || table.Name != tableName {
  68. type User struct {
  69. PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'argon2'"`
  70. }
  71. return x.Sync2(new(User))
  72. }
  73. column := table.GetColumn("passwd_hash_algo")
  74. if column == nil {
  75. type User struct {
  76. PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'argon2'"`
  77. }
  78. return x.Sync2(new(User))
  79. }
  80. sess := x.NewSession()
  81. defer sess.Close()
  82. if err := sess.Begin(); err != nil {
  83. return err
  84. }
  85. tempTableName := "tmp_recreate__user"
  86. column.Default = "'argon2'"
  87. createTableSQL, _ := x.Dialect().CreateTableSQL(table, tempTableName)
  88. for _, sql := range createTableSQL {
  89. if _, err := sess.Exec(sql); err != nil {
  90. log.Error("Unable to create table %s. Error: %v\n", tempTableName, err, createTableSQL)
  91. return err
  92. }
  93. }
  94. for _, index := range table.Indexes {
  95. if _, err := sess.Exec(x.Dialect().CreateIndexSQL(tempTableName, index)); err != nil {
  96. log.Error("Unable to create indexes on temporary table %s. Error: %v", tempTableName, err)
  97. return err
  98. }
  99. }
  100. newTableColumns := table.Columns()
  101. if len(newTableColumns) == 0 {
  102. return fmt.Errorf("no columns in new table")
  103. }
  104. hasID := false
  105. for _, column := range newTableColumns {
  106. hasID = hasID || (column.IsPrimaryKey && column.IsAutoIncrement)
  107. }
  108. sqlStringBuilder := &strings.Builder{}
  109. _, _ = sqlStringBuilder.WriteString("INSERT INTO `")
  110. _, _ = sqlStringBuilder.WriteString(tempTableName)
  111. _, _ = sqlStringBuilder.WriteString("` (`")
  112. _, _ = sqlStringBuilder.WriteString(newTableColumns[0].Name)
  113. _, _ = sqlStringBuilder.WriteString("`")
  114. for _, column := range newTableColumns[1:] {
  115. _, _ = sqlStringBuilder.WriteString(", `")
  116. _, _ = sqlStringBuilder.WriteString(column.Name)
  117. _, _ = sqlStringBuilder.WriteString("`")
  118. }
  119. _, _ = sqlStringBuilder.WriteString(")")
  120. _, _ = sqlStringBuilder.WriteString(" SELECT ")
  121. if newTableColumns[0].Default != "" {
  122. _, _ = sqlStringBuilder.WriteString("COALESCE(`")
  123. _, _ = sqlStringBuilder.WriteString(newTableColumns[0].Name)
  124. _, _ = sqlStringBuilder.WriteString("`, ")
  125. _, _ = sqlStringBuilder.WriteString(newTableColumns[0].Default)
  126. _, _ = sqlStringBuilder.WriteString(")")
  127. } else {
  128. _, _ = sqlStringBuilder.WriteString("`")
  129. _, _ = sqlStringBuilder.WriteString(newTableColumns[0].Name)
  130. _, _ = sqlStringBuilder.WriteString("`")
  131. }
  132. for _, column := range newTableColumns[1:] {
  133. if column.Default != "" {
  134. _, _ = sqlStringBuilder.WriteString(", COALESCE(`")
  135. _, _ = sqlStringBuilder.WriteString(column.Name)
  136. _, _ = sqlStringBuilder.WriteString("`, ")
  137. _, _ = sqlStringBuilder.WriteString(column.Default)
  138. _, _ = sqlStringBuilder.WriteString(")")
  139. } else {
  140. _, _ = sqlStringBuilder.WriteString(", `")
  141. _, _ = sqlStringBuilder.WriteString(column.Name)
  142. _, _ = sqlStringBuilder.WriteString("`")
  143. }
  144. }
  145. _, _ = sqlStringBuilder.WriteString(" FROM `")
  146. _, _ = sqlStringBuilder.WriteString(tableName)
  147. _, _ = sqlStringBuilder.WriteString("`")
  148. if _, err := sess.Exec(sqlStringBuilder.String()); err != nil {
  149. log.Error("Unable to set copy data in to temp table %s. Error: %v", tempTableName, err)
  150. return err
  151. }
  152. // SQLite will drop all the constraints on the old table
  153. if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil {
  154. log.Error("Unable to drop old table %s. Error: %v", tableName, err)
  155. return err
  156. }
  157. for _, index := range table.Indexes {
  158. if _, err := sess.Exec(x.Dialect().DropIndexSQL(tempTableName, index)); err != nil {
  159. log.Error("Unable to drop indexes on temporary table %s. Error: %v", tempTableName, err)
  160. return err
  161. }
  162. }
  163. if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` RENAME TO `%s`", tempTableName, tableName)); err != nil {
  164. log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
  165. return err
  166. }
  167. for _, index := range table.Indexes {
  168. if _, err := sess.Exec(x.Dialect().CreateIndexSQL(tableName, index)); err != nil {
  169. log.Error("Unable to recreate indexes on table %s. Error: %v", tableName, err)
  170. return err
  171. }
  172. }
  173. return sess.Commit()
  174. }