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 141 142 142 - `services.clamsmtp` is unmaintained and was removed from Nixpkgs. 143 143 144 + - `prosody` gained a config check option named `services.prosody.checkConfig` which runs `prosodyctl check config` and is turned on by default. 145 + 144 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`. 145 147 146 148 - `services.dnscrypt-proxy2` gains a `package` option to specify dnscrypt-proxy package to use.
+340 -353
nixos/modules/services/networking/prosody.nix
··· 9 9 let 10 10 cfg = config.services.prosody; 11 11 12 - sslOpts = 13 - { ... }: 14 - { 12 + sslOpts = _: { 13 + options = { 14 + key = mkOption { 15 + type = types.path; 16 + description = "Path to the key file."; 17 + }; 15 18 16 - options = { 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 + }; 17 24 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 - 25 + extraOptions = mkOption { 26 + type = types.attrs; 27 + default = { }; 28 + description = "Extra SSL configuration options."; 35 29 }; 36 30 }; 31 + }; 37 32 38 33 discoOpts = { 39 34 options = { ··· 301 296 }; 302 297 ''; 303 298 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 - }; 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 + }; 384 377 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 - }; 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"; 430 422 }; 431 423 }; 424 + }; 432 425 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 - }; 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"; 468 458 }; 469 459 }; 460 + }; 470 461 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."; 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"; 491 476 }; 477 + options.domain = mkOption { 478 + type = with types; nullOr str; 479 + description = "Domain name for a http_file_share service."; 492 480 }; 481 + }; 493 482 494 - vHostOpts = 495 - { ... }: 496 - { 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 + }; 497 502 498 - options = { 503 + extraConfig = mkOption { 504 + type = types.lines; 505 + default = ""; 506 + description = "Additional virtual host specific configuration"; 507 + }; 508 + }; 509 + }; 499 510 500 - # TODO: require attribute 501 - domain = mkOption { 502 - type = types.str; 503 - description = "Domain name"; 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"; 504 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 + } 505 543 506 - enabled = mkOption { 507 - type = types.bool; 508 - default = false; 509 - description = "Whether to enable the virtual host"; 510 - }; 544 + ${optionalString (cfg.ssl != null) (createSSLOptsStr cfg.ssl)} 511 545 512 - ssl = mkOption { 513 - type = types.nullOr (types.submodule sslOpts); 514 - default = null; 515 - description = "Paths to SSL files"; 516 - }; 546 + admins = ${toLua cfg.admins} 517 547 518 - extraConfig = mkOption { 519 - type = types.lines; 520 - default = ""; 521 - description = "Additional virtual host specific configuration"; 522 - }; 548 + modules_enabled = { 523 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)} 524 555 }; 525 556 526 - }; 557 + disco_items = { 558 + ${lib.concatStringsSep "\n" (builtins.map (x: ''{ "${x.url}", "${x.description}"};'') discoItems)} 559 + }; 527 560 528 - in 561 + allow_registration = ${toLua cfg.allowRegistration} 529 562 530 - { 563 + c2s_require_encryption = ${toLua cfg.c2sRequireEncryption} 531 564 532 - ###### interface 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} 533 569 534 - options = { 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} 535 577 536 - services.prosody = { 578 + ${cfg.extraConfig} 537 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 = { 538 629 enable = mkOption { 539 630 type = types.bool; 540 631 default = false; 541 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`"; 542 640 }; 543 641 544 642 xmppComplianceSuite = mkOption { ··· 818 916 } 819 917 ''; 820 918 }; 821 - 822 919 }; 823 920 }; 824 921 825 - ###### implementation 826 - 827 922 config = mkIf cfg.enable { 828 - 829 923 assertions = 830 924 let 831 925 genericErrMsg = '' ··· 860 954 861 955 environment.systemPackages = [ cfg.package ]; 862 956 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"; 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 ]; 869 962 } 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 - ''; 963 + '' 964 + cp ${configFile} prosody.cfg.lua 965 + prosodyctl --config ./prosody.cfg.lua check config 966 + touch $out 967 + '' 968 + else 969 + configFile; 982 970 983 971 users.users.prosody = mkIf (cfg.user == "prosody") { 984 972 uid = config.ids.uids.prosody; ··· 1025 1013 }) 1026 1014 ]; 1027 1015 }; 1028 - 1029 1016 }; 1030 1017 1031 1018 meta.doc = ./prosody.md;