nixos/prosody: add config check option (#260551)

authored by Sandro and committed by GitHub b0a64354 f8a31163

+342 -353
+2
nixos/doc/manual/release-notes/rl-2511.section.md
··· 141 142 - `services.clamsmtp` is unmaintained and was removed from Nixpkgs. 143 144 - `services.dependency-track` removed its configuration of the JVM heap size. This lets the JVM choose its maximum heap size automatically, which should work much better in practice for most users. For deployments on systems with little RAM, it may now be necessary to manually configure a maximum heap size using {option}`services.dependency-track.javaArgs`. 145 146 - `services.dnscrypt-proxy2` gains a `package` option to specify dnscrypt-proxy package to use.
··· 141 142 - `services.clamsmtp` is unmaintained and was removed from Nixpkgs. 143 144 + - `prosody` gained a config check option named `services.prosody.checkConfig` which runs `prosodyctl check config` and is turned on by default. 145 + 146 - `services.dependency-track` removed its configuration of the JVM heap size. This lets the JVM choose its maximum heap size automatically, which should work much better in practice for most users. For deployments on systems with little RAM, it may now be necessary to manually configure a maximum heap size using {option}`services.dependency-track.javaArgs`. 147 148 - `services.dnscrypt-proxy2` gains a `package` option to specify dnscrypt-proxy package to use.
+340 -353
nixos/modules/services/networking/prosody.nix
··· 9 let 10 cfg = config.services.prosody; 11 12 - sslOpts = 13 - { ... }: 14 - { 15 16 - options = { 17 18 - key = mkOption { 19 - type = types.path; 20 - description = "Path to the key file."; 21 - }; 22 - 23 - # TODO: rename to certificate to match the prosody config 24 - cert = mkOption { 25 - type = types.path; 26 - description = "Path to the certificate file."; 27 - }; 28 - 29 - extraOptions = mkOption { 30 - type = types.attrs; 31 - default = { }; 32 - description = "Extra SSL configuration options."; 33 - }; 34 - 35 }; 36 }; 37 38 discoOpts = { 39 options = { ··· 301 }; 302 ''; 303 304 - mucOpts = 305 - { ... }: 306 - { 307 - options = { 308 - domain = mkOption { 309 - type = types.str; 310 - description = "Domain name of the MUC"; 311 - }; 312 - name = mkOption { 313 - type = types.str; 314 - description = "The name to return in service discovery responses for the MUC service itself"; 315 - default = "Prosody Chatrooms"; 316 - }; 317 - restrictRoomCreation = mkOption { 318 - type = types.enum [ 319 - true 320 - false 321 - "admin" 322 - "local" 323 - ]; 324 - default = false; 325 - description = "Restrict room creation to server admins"; 326 - }; 327 - maxHistoryMessages = mkOption { 328 - type = types.int; 329 - default = 20; 330 - description = "Specifies a limit on what each room can be configured to keep"; 331 - }; 332 - roomLocking = mkOption { 333 - type = types.bool; 334 - default = true; 335 - description = '' 336 - Enables room locking, which means that a room must be 337 - configured before it can be used. Locked rooms are invisible 338 - and cannot be entered by anyone but the creator 339 - ''; 340 - }; 341 - roomLockTimeout = mkOption { 342 - type = types.int; 343 - default = 300; 344 - description = '' 345 - Timeout after which the room is destroyed or unlocked if not 346 - configured, in seconds 347 - ''; 348 - }; 349 - tombstones = mkOption { 350 - type = types.bool; 351 - default = true; 352 - description = '' 353 - When a room is destroyed, it leaves behind a tombstone which 354 - prevents the room being entered or recreated. It also allows 355 - anyone who was not in the room at the time it was destroyed 356 - to learn about it, and to update their bookmarks. Tombstones 357 - prevents the case where someone could recreate a previously 358 - semi-anonymous room in order to learn the real JIDs of those 359 - who often join there. 360 - ''; 361 - }; 362 - tombstoneExpiry = mkOption { 363 - type = types.int; 364 - default = 2678400; 365 - description = '' 366 - This settings controls how long a tombstone is considered 367 - valid. It defaults to 31 days. After this time, the room in 368 - question can be created again. 369 - ''; 370 - }; 371 - allowners_muc = mkOption { 372 - type = types.bool; 373 - default = false; 374 - description = '' 375 - Add module allowners, any user in chat is able to 376 - kick other. Usefull in jitsi-meet to kick ghosts. 377 - ''; 378 - }; 379 - vcard_muc = mkOption { 380 - type = types.bool; 381 - default = true; 382 - description = "Adds the ability to set vCard for Multi User Chat rooms"; 383 - }; 384 385 - # Extra parameters. Defaulting to prosody default values. 386 - # Adding them explicitly to make them visible from the options 387 - # documentation. 388 - # 389 - # See https://prosody.im/doc/modules/mod_muc for more details. 390 - roomDefaultPublic = mkOption { 391 - type = types.bool; 392 - default = true; 393 - description = "If set, the MUC rooms will be public by default."; 394 - }; 395 - roomDefaultMembersOnly = mkOption { 396 - type = types.bool; 397 - default = false; 398 - description = "If set, the MUC rooms will only be accessible to the members by default."; 399 - }; 400 - roomDefaultModerated = mkOption { 401 - type = types.bool; 402 - default = false; 403 - description = "If set, the MUC rooms will be moderated by default."; 404 - }; 405 - roomDefaultPublicJids = mkOption { 406 - type = types.bool; 407 - default = false; 408 - description = "If set, the MUC rooms will display the public JIDs by default."; 409 - }; 410 - roomDefaultChangeSubject = mkOption { 411 - type = types.bool; 412 - default = false; 413 - description = "If set, the rooms will display the public JIDs by default."; 414 - }; 415 - roomDefaultHistoryLength = mkOption { 416 - type = types.int; 417 - default = 20; 418 - description = "Number of history message sent to participants by default."; 419 - }; 420 - roomDefaultLanguage = mkOption { 421 - type = types.str; 422 - default = "en"; 423 - description = "Default room language."; 424 - }; 425 - extraConfig = mkOption { 426 - type = types.lines; 427 - default = ""; 428 - description = "Additional MUC specific configuration"; 429 - }; 430 }; 431 }; 432 433 - uploadHttpOpts = 434 - { ... }: 435 - { 436 - options = { 437 - domain = mkOption { 438 - type = types.nullOr types.str; 439 - description = "Domain name for the http-upload service"; 440 - }; 441 - uploadFileSizeLimit = mkOption { 442 - type = types.str; 443 - default = "50 * 1024 * 1024"; 444 - description = "Maximum file size, in bytes. Defaults to 50MB."; 445 - }; 446 - uploadExpireAfter = mkOption { 447 - type = types.str; 448 - default = "60 * 60 * 24 * 7"; 449 - description = "Max age of a file before it gets deleted, in seconds."; 450 - }; 451 - userQuota = mkOption { 452 - type = types.nullOr types.int; 453 - default = null; 454 - example = 1234; 455 - description = '' 456 - Maximum size of all uploaded files per user, in bytes. There 457 - will be no quota if this option is set to null. 458 - ''; 459 - }; 460 - httpUploadPath = mkOption { 461 - type = types.str; 462 - description = '' 463 - Directory where the uploaded files will be stored when the http_upload module is used. 464 - By default, uploaded files are put in a sub-directory of the default Prosody storage path (usually /var/lib/prosody). 465 - ''; 466 - default = "/var/lib/prosody"; 467 - }; 468 }; 469 }; 470 471 - httpFileShareOpts = 472 - { ... }: 473 - { 474 - freeformType = 475 - with types; 476 - let 477 - atom = oneOf [ 478 - int 479 - bool 480 - str 481 - (listOf atom) 482 - ]; 483 - in 484 - attrsOf (nullOr atom) 485 - // { 486 - description = "int, bool, string or list of them"; 487 - }; 488 - options.domain = mkOption { 489 - type = with types; nullOr str; 490 - description = "Domain name for a http_file_share service."; 491 }; 492 }; 493 494 - vHostOpts = 495 - { ... }: 496 - { 497 498 - options = { 499 500 - # TODO: require attribute 501 - domain = mkOption { 502 - type = types.str; 503 - description = "Domain name"; 504 }; 505 506 - enabled = mkOption { 507 - type = types.bool; 508 - default = false; 509 - description = "Whether to enable the virtual host"; 510 - }; 511 512 - ssl = mkOption { 513 - type = types.nullOr (types.submodule sslOpts); 514 - default = null; 515 - description = "Paths to SSL files"; 516 - }; 517 518 - extraConfig = mkOption { 519 - type = types.lines; 520 - default = ""; 521 - description = "Additional virtual host specific configuration"; 522 - }; 523 524 }; 525 526 - }; 527 528 - in 529 530 - { 531 532 - ###### interface 533 534 - options = { 535 536 - services.prosody = { 537 538 enable = mkOption { 539 type = types.bool; 540 default = false; 541 description = "Whether to enable the prosody server"; 542 }; 543 544 xmppComplianceSuite = mkOption { ··· 818 } 819 ''; 820 }; 821 - 822 }; 823 }; 824 825 - ###### implementation 826 - 827 config = mkIf cfg.enable { 828 - 829 assertions = 830 let 831 genericErrMsg = '' ··· 860 861 environment.systemPackages = [ cfg.package ]; 862 863 - environment.etc."prosody/prosody.cfg.lua".text = 864 - let 865 - httpDiscoItems = 866 - optional (cfg.uploadHttp != null) { 867 - url = cfg.uploadHttp.domain; 868 - description = "HTTP upload endpoint"; 869 } 870 - ++ optional (cfg.httpFileShare != null) { 871 - url = cfg.httpFileShare.domain; 872 - description = "HTTP file share endpoint"; 873 - }; 874 - mucDiscoItems = builtins.foldl' ( 875 - acc: muc: 876 - [ 877 - { 878 - url = muc.domain; 879 - description = "${muc.domain} MUC endpoint"; 880 - } 881 - ] 882 - ++ acc 883 - ) [ ] cfg.muc; 884 - discoItems = cfg.disco_items ++ httpDiscoItems ++ mucDiscoItems; 885 - in 886 - '' 887 - 888 - pidfile = "/run/prosody/prosody.pid" 889 - 890 - log = ${cfg.log} 891 - 892 - data_path = "${cfg.dataDir}" 893 - plugin_paths = { 894 - ${lib.concatStringsSep ", " (map (n: "\"${n}\"") cfg.extraPluginPaths)} 895 - } 896 - 897 - ${optionalString (cfg.ssl != null) (createSSLOptsStr cfg.ssl)} 898 - 899 - admins = ${toLua cfg.admins} 900 - 901 - modules_enabled = { 902 - 903 - ${lib.concatStringsSep "\n " ( 904 - lib.mapAttrsToList (name: val: optionalString val "${toLua name};") cfg.modules 905 - )} 906 - ${lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.package.communityModules)} 907 - ${lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.extraModules)} 908 - }; 909 - 910 - disco_items = { 911 - ${lib.concatStringsSep "\n" (builtins.map (x: ''{ "${x.url}", "${x.description}"};'') discoItems)} 912 - }; 913 - 914 - allow_registration = ${toLua cfg.allowRegistration} 915 - 916 - c2s_require_encryption = ${toLua cfg.c2sRequireEncryption} 917 - 918 - s2s_require_encryption = ${toLua cfg.s2sRequireEncryption} 919 - 920 - s2s_secure_auth = ${toLua cfg.s2sSecureAuth} 921 - 922 - s2s_insecure_domains = ${toLua cfg.s2sInsecureDomains} 923 - 924 - s2s_secure_domains = ${toLua cfg.s2sSecureDomains} 925 - 926 - authentication = ${toLua cfg.authentication} 927 - 928 - http_interfaces = ${toLua cfg.httpInterfaces} 929 - 930 - https_interfaces = ${toLua cfg.httpsInterfaces} 931 - 932 - http_ports = ${toLua cfg.httpPorts} 933 - 934 - https_ports = ${toLua cfg.httpsPorts} 935 - 936 - ${cfg.extraConfig} 937 - 938 - ${lib.concatMapStrings (muc: '' 939 - Component ${toLua muc.domain} "muc" 940 - modules_enabled = { "muc_mam"; ${optionalString muc.vcard_muc ''"vcard_muc";''} ${optionalString muc.allowners_muc ''"muc_allowners";''} } 941 - name = ${toLua muc.name} 942 - restrict_room_creation = ${toLua muc.restrictRoomCreation} 943 - max_history_messages = ${toLua muc.maxHistoryMessages} 944 - muc_room_locking = ${toLua muc.roomLocking} 945 - muc_room_lock_timeout = ${toLua muc.roomLockTimeout} 946 - muc_tombstones = ${toLua muc.tombstones} 947 - muc_tombstone_expiry = ${toLua muc.tombstoneExpiry} 948 - muc_room_default_public = ${toLua muc.roomDefaultPublic} 949 - muc_room_default_members_only = ${toLua muc.roomDefaultMembersOnly} 950 - muc_room_default_moderated = ${toLua muc.roomDefaultModerated} 951 - muc_room_default_public_jids = ${toLua muc.roomDefaultPublicJids} 952 - muc_room_default_change_subject = ${toLua muc.roomDefaultChangeSubject} 953 - muc_room_default_history_length = ${toLua muc.roomDefaultHistoryLength} 954 - muc_room_default_language = ${toLua muc.roomDefaultLanguage} 955 - ${muc.extraConfig} 956 - '') cfg.muc} 957 - 958 - ${lib.optionalString (cfg.uploadHttp != null) '' 959 - Component ${toLua cfg.uploadHttp.domain} "http_upload" 960 - http_upload_file_size_limit = ${cfg.uploadHttp.uploadFileSizeLimit} 961 - http_upload_expire_after = ${cfg.uploadHttp.uploadExpireAfter} 962 - ${lib.optionalString ( 963 - cfg.uploadHttp.userQuota != null 964 - ) "http_upload_quota = ${toLua cfg.uploadHttp.userQuota}"} 965 - http_upload_path = ${toLua cfg.uploadHttp.httpUploadPath} 966 - ''} 967 - 968 - ${lib.optionalString (cfg.httpFileShare != null) '' 969 - Component ${toLua cfg.httpFileShare.domain} "http_file_share" 970 - ${settingsToLua " http_file_share_" (cfg.httpFileShare // { domain = null; })} 971 - ''} 972 - 973 - ${lib.concatStringsSep "\n" ( 974 - lib.mapAttrsToList (n: v: '' 975 - VirtualHost "${v.domain}" 976 - enabled = ${boolToString v.enabled}; 977 - ${optionalString (v.ssl != null) (createSSLOptsStr v.ssl)} 978 - ${v.extraConfig} 979 - '') cfg.virtualHosts 980 - )} 981 - ''; 982 983 users.users.prosody = mkIf (cfg.user == "prosody") { 984 uid = config.ids.uids.prosody; ··· 1025 }) 1026 ]; 1027 }; 1028 - 1029 }; 1030 1031 meta.doc = ./prosody.md;
··· 9 let 10 cfg = config.services.prosody; 11 12 + sslOpts = _: { 13 + options = { 14 + key = mkOption { 15 + type = types.path; 16 + description = "Path to the key file."; 17 + }; 18 19 + # TODO: rename to certificate to match the prosody config 20 + cert = mkOption { 21 + type = types.path; 22 + description = "Path to the certificate file."; 23 + }; 24 25 + extraOptions = mkOption { 26 + type = types.attrs; 27 + default = { }; 28 + description = "Extra SSL configuration options."; 29 }; 30 }; 31 + }; 32 33 discoOpts = { 34 options = { ··· 296 }; 297 ''; 298 299 + mucOpts = _: { 300 + options = { 301 + domain = mkOption { 302 + type = types.str; 303 + description = "Domain name of the MUC"; 304 + }; 305 + name = mkOption { 306 + type = types.str; 307 + description = "The name to return in service discovery responses for the MUC service itself"; 308 + default = "Prosody Chatrooms"; 309 + }; 310 + restrictRoomCreation = mkOption { 311 + type = types.enum [ 312 + true 313 + false 314 + "admin" 315 + "local" 316 + ]; 317 + default = false; 318 + description = "Restrict room creation to server admins"; 319 + }; 320 + maxHistoryMessages = mkOption { 321 + type = types.int; 322 + default = 20; 323 + description = "Specifies a limit on what each room can be configured to keep"; 324 + }; 325 + roomLocking = mkOption { 326 + type = types.bool; 327 + default = true; 328 + description = '' 329 + Enables room locking, which means that a room must be 330 + configured before it can be used. Locked rooms are invisible 331 + and cannot be entered by anyone but the creator 332 + ''; 333 + }; 334 + roomLockTimeout = mkOption { 335 + type = types.int; 336 + default = 300; 337 + description = '' 338 + Timeout after which the room is destroyed or unlocked if not 339 + configured, in seconds 340 + ''; 341 + }; 342 + tombstones = mkOption { 343 + type = types.bool; 344 + default = true; 345 + description = '' 346 + When a room is destroyed, it leaves behind a tombstone which 347 + prevents the room being entered or recreated. It also allows 348 + anyone who was not in the room at the time it was destroyed 349 + to learn about it, and to update their bookmarks. Tombstones 350 + prevents the case where someone could recreate a previously 351 + semi-anonymous room in order to learn the real JIDs of those 352 + who often join there. 353 + ''; 354 + }; 355 + tombstoneExpiry = mkOption { 356 + type = types.int; 357 + default = 2678400; 358 + description = '' 359 + This settings controls how long a tombstone is considered 360 + valid. It defaults to 31 days. After this time, the room in 361 + question can be created again. 362 + ''; 363 + }; 364 + allowners_muc = mkOption { 365 + type = types.bool; 366 + default = false; 367 + description = '' 368 + Add module allowners, any user in chat is able to 369 + kick other. Useful in jitsi-meet to kick ghosts. 370 + ''; 371 + }; 372 + vcard_muc = mkOption { 373 + type = types.bool; 374 + default = true; 375 + description = "Adds the ability to set vCard for Multi User Chat rooms"; 376 + }; 377 378 + # Extra parameters. Defaulting to prosody default values. 379 + # Adding them explicitly to make them visible from the options 380 + # documentation. 381 + # 382 + # See https://prosody.im/doc/modules/mod_muc for more details. 383 + roomDefaultPublic = mkOption { 384 + type = types.bool; 385 + default = true; 386 + description = "If set, the MUC rooms will be public by default."; 387 + }; 388 + roomDefaultMembersOnly = mkOption { 389 + type = types.bool; 390 + default = false; 391 + description = "If set, the MUC rooms will only be accessible to the members by default."; 392 + }; 393 + roomDefaultModerated = mkOption { 394 + type = types.bool; 395 + default = false; 396 + description = "If set, the MUC rooms will be moderated by default."; 397 + }; 398 + roomDefaultPublicJids = mkOption { 399 + type = types.bool; 400 + default = false; 401 + description = "If set, the MUC rooms will display the public JIDs by default."; 402 + }; 403 + roomDefaultChangeSubject = mkOption { 404 + type = types.bool; 405 + default = false; 406 + description = "If set, the rooms will display the public JIDs by default."; 407 + }; 408 + roomDefaultHistoryLength = mkOption { 409 + type = types.int; 410 + default = 20; 411 + description = "Number of history message sent to participants by default."; 412 + }; 413 + roomDefaultLanguage = mkOption { 414 + type = types.str; 415 + default = "en"; 416 + description = "Default room language."; 417 + }; 418 + extraConfig = mkOption { 419 + type = types.lines; 420 + default = ""; 421 + description = "Additional MUC specific configuration"; 422 }; 423 }; 424 + }; 425 426 + uploadHttpOpts = _: { 427 + options = { 428 + domain = mkOption { 429 + type = types.nullOr types.str; 430 + description = "Domain name for the http-upload service"; 431 + }; 432 + uploadFileSizeLimit = mkOption { 433 + type = types.str; 434 + default = "50 * 1024 * 1024"; 435 + description = "Maximum file size, in bytes. Defaults to 50MB."; 436 + }; 437 + uploadExpireAfter = mkOption { 438 + type = types.str; 439 + default = "60 * 60 * 24 * 7"; 440 + description = "Max age of a file before it gets deleted, in seconds."; 441 + }; 442 + userQuota = mkOption { 443 + type = types.nullOr types.int; 444 + default = null; 445 + example = 1234; 446 + description = '' 447 + Maximum size of all uploaded files per user, in bytes. There 448 + will be no quota if this option is set to null. 449 + ''; 450 + }; 451 + httpUploadPath = mkOption { 452 + type = types.str; 453 + description = '' 454 + Directory where the uploaded files will be stored when the http_upload module is used. 455 + By default, uploaded files are put in a sub-directory of the default Prosody storage path (usually /var/lib/prosody). 456 + ''; 457 + default = "/var/lib/prosody"; 458 }; 459 }; 460 + }; 461 462 + httpFileShareOpts = _: { 463 + freeformType = 464 + with types; 465 + let 466 + atom = oneOf [ 467 + int 468 + bool 469 + str 470 + (listOf atom) 471 + ]; 472 + in 473 + attrsOf (nullOr atom) 474 + // { 475 + description = "int, bool, string or list of them"; 476 }; 477 + options.domain = mkOption { 478 + type = with types; nullOr str; 479 + description = "Domain name for a http_file_share service."; 480 }; 481 + }; 482 483 + vHostOpts = _: { 484 + options = { 485 + # TODO: require attribute 486 + domain = mkOption { 487 + type = types.str; 488 + description = "Domain name"; 489 + }; 490 + 491 + enabled = mkOption { 492 + type = types.bool; 493 + default = false; 494 + description = "Whether to enable the virtual host"; 495 + }; 496 + 497 + ssl = mkOption { 498 + type = types.nullOr (types.submodule sslOpts); 499 + default = null; 500 + description = "Paths to SSL files"; 501 + }; 502 503 + extraConfig = mkOption { 504 + type = types.lines; 505 + default = ""; 506 + description = "Additional virtual host specific configuration"; 507 + }; 508 + }; 509 + }; 510 511 + configFile = 512 + let 513 + httpDiscoItems = 514 + optional (cfg.uploadHttp != null) { 515 + url = cfg.uploadHttp.domain; 516 + description = "HTTP upload endpoint"; 517 + } 518 + ++ optional (cfg.httpFileShare != null) { 519 + url = cfg.httpFileShare.domain; 520 + description = "HTTP file share endpoint"; 521 }; 522 + mucDiscoItems = builtins.foldl' ( 523 + acc: muc: 524 + [ 525 + { 526 + url = muc.domain; 527 + description = "${muc.domain} MUC endpoint"; 528 + } 529 + ] 530 + ++ acc 531 + ) [ ] cfg.muc; 532 + discoItems = cfg.disco_items ++ httpDiscoItems ++ mucDiscoItems; 533 + in 534 + pkgs.writeText "prosody.cfg.lua" '' 535 + pidfile = "/run/prosody/prosody.pid" 536 + 537 + log = ${cfg.log} 538 + 539 + data_path = "${cfg.dataDir}" 540 + plugin_paths = { 541 + ${lib.concatStringsSep ", " (map (n: "\"${n}\"") cfg.extraPluginPaths)} 542 + } 543 544 + ${optionalString (cfg.ssl != null) (createSSLOptsStr cfg.ssl)} 545 546 + admins = ${toLua cfg.admins} 547 548 + modules_enabled = { 549 550 + ${lib.concatStringsSep "\n " ( 551 + lib.mapAttrsToList (name: val: optionalString val "${toLua name};") cfg.modules 552 + )} 553 + ${lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.package.communityModules)} 554 + ${lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.extraModules)} 555 }; 556 557 + disco_items = { 558 + ${lib.concatStringsSep "\n" (builtins.map (x: ''{ "${x.url}", "${x.description}"};'') discoItems)} 559 + }; 560 561 + allow_registration = ${toLua cfg.allowRegistration} 562 563 + c2s_require_encryption = ${toLua cfg.c2sRequireEncryption} 564 565 + s2s_require_encryption = ${toLua cfg.s2sRequireEncryption} 566 + s2s_secure_auth = ${toLua cfg.s2sSecureAuth} 567 + s2s_insecure_domains = ${toLua cfg.s2sInsecureDomains} 568 + s2s_secure_domains = ${toLua cfg.s2sSecureDomains} 569 570 + authentication = ${toLua cfg.authentication} 571 + 572 + http_interfaces = ${toLua cfg.httpInterfaces} 573 + https_interfaces = ${toLua cfg.httpsInterfaces} 574 + 575 + http_ports = ${toLua cfg.httpPorts} 576 + https_ports = ${toLua cfg.httpsPorts} 577 578 + ${cfg.extraConfig} 579 580 + ${lib.concatMapStrings (muc: '' 581 + Component ${toLua muc.domain} "muc" 582 + modules_enabled = { "muc_mam"; ${optionalString muc.vcard_muc ''"vcard_muc";''} ${optionalString muc.allowners_muc ''"muc_allowners";''} } 583 + name = ${toLua muc.name} 584 + restrict_room_creation = ${toLua muc.restrictRoomCreation} 585 + max_history_messages = ${toLua muc.maxHistoryMessages} 586 + muc_room_locking = ${toLua muc.roomLocking} 587 + muc_room_lock_timeout = ${toLua muc.roomLockTimeout} 588 + muc_tombstones = ${toLua muc.tombstones} 589 + muc_tombstone_expiry = ${toLua muc.tombstoneExpiry} 590 + muc_room_default_public = ${toLua muc.roomDefaultPublic} 591 + muc_room_default_members_only = ${toLua muc.roomDefaultMembersOnly} 592 + muc_room_default_moderated = ${toLua muc.roomDefaultModerated} 593 + muc_room_default_public_jids = ${toLua muc.roomDefaultPublicJids} 594 + muc_room_default_change_subject = ${toLua muc.roomDefaultChangeSubject} 595 + muc_room_default_history_length = ${toLua muc.roomDefaultHistoryLength} 596 + muc_room_default_language = ${toLua muc.roomDefaultLanguage} 597 + ${muc.extraConfig} 598 + '') cfg.muc} 599 + 600 + ${lib.optionalString (cfg.uploadHttp != null) '' 601 + Component ${toLua cfg.uploadHttp.domain} "http_upload" 602 + http_upload_file_size_limit = ${cfg.uploadHttp.uploadFileSizeLimit} 603 + http_upload_expire_after = ${cfg.uploadHttp.uploadExpireAfter} 604 + ${lib.optionalString ( 605 + cfg.uploadHttp.userQuota != null 606 + ) "http_upload_quota = ${toLua cfg.uploadHttp.userQuota}"} 607 + http_upload_path = ${toLua cfg.uploadHttp.httpUploadPath} 608 + ''} 609 + 610 + ${lib.optionalString (cfg.httpFileShare != null) '' 611 + Component ${toLua cfg.httpFileShare.domain} "http_file_share" 612 + ${settingsToLua " http_file_share_" (cfg.httpFileShare // { domain = null; })} 613 + ''} 614 + 615 + ${lib.concatStringsSep "\n" ( 616 + lib.mapAttrsToList (n: v: '' 617 + VirtualHost "${v.domain}" 618 + enabled = ${boolToString v.enabled}; 619 + ${optionalString (v.ssl != null) (createSSLOptsStr v.ssl)} 620 + ${v.extraConfig} 621 + '') cfg.virtualHosts 622 + )} 623 + ''; 624 + 625 + in 626 + { 627 + options = { 628 + services.prosody = { 629 enable = mkOption { 630 type = types.bool; 631 default = false; 632 description = "Whether to enable the prosody server"; 633 + }; 634 + 635 + checkConfig = mkOption { 636 + type = types.bool; 637 + default = true; 638 + example = false; 639 + description = "Check the configuration file with `prosodyctl check config`"; 640 }; 641 642 xmppComplianceSuite = mkOption { ··· 916 } 917 ''; 918 }; 919 }; 920 }; 921 922 config = mkIf cfg.enable { 923 assertions = 924 let 925 genericErrMsg = '' ··· 954 955 environment.systemPackages = [ cfg.package ]; 956 957 + environment.etc."prosody/prosody.cfg.lua".source = 958 + if cfg.checkConfig then 959 + pkgs.runCommandLocal "prosody.cfg.lua-checked" 960 + { 961 + nativeBuildInputs = [ cfg.package ]; 962 } 963 + '' 964 + cp ${configFile} prosody.cfg.lua 965 + prosodyctl --config ./prosody.cfg.lua check config 966 + touch $out 967 + '' 968 + else 969 + configFile; 970 971 users.users.prosody = mkIf (cfg.user == "prosody") { 972 uid = config.ids.uids.prosody; ··· 1013 }) 1014 ]; 1015 }; 1016 }; 1017 1018 meta.doc = ./prosody.md;