This repository has no description git.sr.ht/~singpolyma/sgx-endstream
xmpp jabber sopranica sgx
0

Configure Feed

Select the types of activity you want to include in your feed.

Initial commit

author
Stephen Paul Weber
date (May 14, 2024, 9:11 PM -0500) commit dd57a2b0
+1487
+3
.gitignore
··· 1 + Gemfile.lock 2 + .gems 3 + .bundle
+147
.rubocop.yml
··· 1 + AllCops: 2 + TargetRubyVersion: 2.5 3 + NewCops: enable 4 + 5 + Metrics/ClassLength: 6 + CountAsOne: 7 + - heredoc 8 + Exclude: 9 + - test/* 10 + 11 + Metrics/MethodLength: 12 + Exclude: 13 + - test/* 14 + 15 + Metrics/BlockLength: 16 + Exclude: 17 + - test/* 18 + 19 + Metrics/AbcSize: 20 + Exclude: 21 + - test/* 22 + 23 + Metrics/ParameterLists: 24 + Max: 8 25 + 26 + Naming/MethodParameterName: 27 + AllowNamesEndingInNumbers: false 28 + AllowedNames: 29 + - io 30 + - m 31 + - e 32 + - q 33 + - s 34 + - k 35 + - v 36 + - ex 37 + - tx 38 + - id 39 + - iq 40 + - db 41 + - to 42 + - tn 43 + 44 + Layout/IndentationStyle: 45 + Enabled: false 46 + EnforcedStyle: tabs 47 + IndentationWidth: 2 48 + 49 + Layout/IndentationWidth: 50 + Width: 1 # one tab 51 + 52 + Layout/LineLength: 53 + Max: 80 54 + Exclude: 55 + - Gemfile 56 + 57 + Layout/EndAlignment: 58 + EnforcedStyleAlignWith: start_of_line 59 + 60 + Layout/SpaceAroundEqualsInParameterDefault: 61 + EnforcedStyle: no_space 62 + 63 + Layout/AccessModifierIndentation: 64 + EnforcedStyle: outdent 65 + 66 + Layout/FirstParameterIndentation: 67 + EnforcedStyle: consistent 68 + 69 + Layout/MultilineMethodCallIndentation: 70 + EnforcedStyle: indented 71 + 72 + Style/AccessModifierDeclarations: 73 + Enabled: false 74 + 75 + Style/ArrayCoercion: 76 + Enabled: false 77 + 78 + Style/StringLiterals: 79 + EnforcedStyle: double_quotes 80 + 81 + Style/NumericLiterals: 82 + Enabled: false 83 + 84 + Style/SymbolArray: 85 + EnforcedStyle: brackets 86 + 87 + Style/WordArray: 88 + EnforcedStyle: brackets 89 + 90 + Style/Documentation: 91 + Enabled: false 92 + 93 + Style/DoubleNegation: 94 + EnforcedStyle: allowed_in_returns 95 + Enabled: false 96 + 97 + Style/ParallelAssignment: 98 + Enabled: false 99 + 100 + Style/PerlBackrefs: 101 + Enabled: false 102 + 103 + Style/SpecialGlobalVars: 104 + EnforcedStyle: use_perl_names 105 + 106 + Style/RegexpLiteral: 107 + EnforcedStyle: slashes 108 + AllowInnerSlashes: true 109 + 110 + Lint/OutOfRangeRegexpRef: 111 + Enabled: false 112 + 113 + Lint/MissingSuper: 114 + Enabled: false 115 + 116 + Lint/ConstantDefinitionInBlock: 117 + AllowedMethods: 118 + - when_ready 119 + 120 + Style/BlockDelimiters: 121 + EnforcedStyle: semantic 122 + AllowBracesOnProceduralOneLiners: true 123 + ProceduralMethods: 124 + - execute_command 125 + - new 126 + 127 + Style/MultilineBlockChain: 128 + Enabled: false 129 + 130 + Layout/FirstArgumentIndentation: 131 + EnforcedStyle: consistent 132 + 133 + Layout/FirstArrayElementIndentation: 134 + EnforcedStyle: consistent 135 + 136 + Style/FormatString: 137 + EnforcedStyle: percent 138 + 139 + Style/FormatStringToken: 140 + EnforcedStyle: unannotated 141 + 142 + Style/FrozenStringLiteralComment: 143 + Exclude: 144 + - forms/**/*.rb 145 + 146 + Naming/AccessorMethodName: 147 + Enabled: false
+661
COPYING
··· 1 + GNU AFFERO GENERAL PUBLIC LICENSE 2 + Version 3, 19 November 2007 3 + 4 + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> 5 + Everyone is permitted to copy and distribute verbatim copies 6 + of this license document, but changing it is not allowed. 7 + 8 + Preamble 9 + 10 + The GNU Affero General Public License is a free, copyleft license for 11 + software and other kinds of works, specifically designed to ensure 12 + cooperation with the community in the case of network server software. 13 + 14 + The licenses for most software and other practical works are designed 15 + to take away your freedom to share and change the works. By contrast, 16 + our General Public Licenses are intended to guarantee your freedom to 17 + share and change all versions of a program--to make sure it remains free 18 + software for all its users. 19 + 20 + When we speak of free software, we are referring to freedom, not 21 + price. Our General Public Licenses are designed to make sure that you 22 + have the freedom to distribute copies of free software (and charge for 23 + them if you wish), that you receive source code or can get it if you 24 + want it, that you can change the software or use pieces of it in new 25 + free programs, and that you know you can do these things. 26 + 27 + Developers that use our General Public Licenses protect your rights 28 + with two steps: (1) assert copyright on the software, and (2) offer 29 + you this License which gives you legal permission to copy, distribute 30 + and/or modify the software. 31 + 32 + A secondary benefit of defending all users' freedom is that 33 + improvements made in alternate versions of the program, if they 34 + receive widespread use, become available for other developers to 35 + incorporate. Many developers of free software are heartened and 36 + encouraged by the resulting cooperation. However, in the case of 37 + software used on network servers, this result may fail to come about. 38 + The GNU General Public License permits making a modified version and 39 + letting the public access it on a server without ever releasing its 40 + source code to the public. 41 + 42 + The GNU Affero General Public License is designed specifically to 43 + ensure that, in such cases, the modified source code becomes available 44 + to the community. It requires the operator of a network server to 45 + provide the source code of the modified version running there to the 46 + users of that server. Therefore, public use of a modified version, on 47 + a publicly accessible server, gives the public access to the source 48 + code of the modified version. 49 + 50 + An older license, called the Affero General Public License and 51 + published by Affero, was designed to accomplish similar goals. This is 52 + a different license, not a version of the Affero GPL, but Affero has 53 + released a new version of the Affero GPL which permits relicensing under 54 + this license. 55 + 56 + The precise terms and conditions for copying, distribution and 57 + modification follow. 58 + 59 + TERMS AND CONDITIONS 60 + 61 + 0. Definitions. 62 + 63 + "This License" refers to version 3 of the GNU Affero General Public License. 64 + 65 + "Copyright" also means copyright-like laws that apply to other kinds of 66 + works, such as semiconductor masks. 67 + 68 + "The Program" refers to any copyrightable work licensed under this 69 + License. Each licensee is addressed as "you". "Licensees" and 70 + "recipients" may be individuals or organizations. 71 + 72 + To "modify" a work means to copy from or adapt all or part of the work 73 + in a fashion requiring copyright permission, other than the making of an 74 + exact copy. The resulting work is called a "modified version" of the 75 + earlier work or a work "based on" the earlier work. 76 + 77 + A "covered work" means either the unmodified Program or a work based 78 + on the Program. 79 + 80 + To "propagate" a work means to do anything with it that, without 81 + permission, would make you directly or secondarily liable for 82 + infringement under applicable copyright law, except executing it on a 83 + computer or modifying a private copy. Propagation includes copying, 84 + distribution (with or without modification), making available to the 85 + public, and in some countries other activities as well. 86 + 87 + To "convey" a work means any kind of propagation that enables other 88 + parties to make or receive copies. Mere interaction with a user through 89 + a computer network, with no transfer of a copy, is not conveying. 90 + 91 + An interactive user interface displays "Appropriate Legal Notices" 92 + to the extent that it includes a convenient and prominently visible 93 + feature that (1) displays an appropriate copyright notice, and (2) 94 + tells the user that there is no warranty for the work (except to the 95 + extent that warranties are provided), that licensees may convey the 96 + work under this License, and how to view a copy of this License. If 97 + the interface presents a list of user commands or options, such as a 98 + menu, a prominent item in the list meets this criterion. 99 + 100 + 1. Source Code. 101 + 102 + The "source code" for a work means the preferred form of the work 103 + for making modifications to it. "Object code" means any non-source 104 + form of a work. 105 + 106 + A "Standard Interface" means an interface that either is an official 107 + standard defined by a recognized standards body, or, in the case of 108 + interfaces specified for a particular programming language, one that 109 + is widely used among developers working in that language. 110 + 111 + The "System Libraries" of an executable work include anything, other 112 + than the work as a whole, that (a) is included in the normal form of 113 + packaging a Major Component, but which is not part of that Major 114 + Component, and (b) serves only to enable use of the work with that 115 + Major Component, or to implement a Standard Interface for which an 116 + implementation is available to the public in source code form. A 117 + "Major Component", in this context, means a major essential component 118 + (kernel, window system, and so on) of the specific operating system 119 + (if any) on which the executable work runs, or a compiler used to 120 + produce the work, or an object code interpreter used to run it. 121 + 122 + The "Corresponding Source" for a work in object code form means all 123 + the source code needed to generate, install, and (for an executable 124 + work) run the object code and to modify the work, including scripts to 125 + control those activities. However, it does not include the work's 126 + System Libraries, or general-purpose tools or generally available free 127 + programs which are used unmodified in performing those activities but 128 + which are not part of the work. For example, Corresponding Source 129 + includes interface definition files associated with source files for 130 + the work, and the source code for shared libraries and dynamically 131 + linked subprograms that the work is specifically designed to require, 132 + such as by intimate data communication or control flow between those 133 + subprograms and other parts of the work. 134 + 135 + The Corresponding Source need not include anything that users 136 + can regenerate automatically from other parts of the Corresponding 137 + Source. 138 + 139 + The Corresponding Source for a work in source code form is that 140 + same work. 141 + 142 + 2. Basic Permissions. 143 + 144 + All rights granted under this License are granted for the term of 145 + copyright on the Program, and are irrevocable provided the stated 146 + conditions are met. This License explicitly affirms your unlimited 147 + permission to run the unmodified Program. The output from running a 148 + covered work is covered by this License only if the output, given its 149 + content, constitutes a covered work. This License acknowledges your 150 + rights of fair use or other equivalent, as provided by copyright law. 151 + 152 + You may make, run and propagate covered works that you do not 153 + convey, without conditions so long as your license otherwise remains 154 + in force. You may convey covered works to others for the sole purpose 155 + of having them make modifications exclusively for you, or provide you 156 + with facilities for running those works, provided that you comply with 157 + the terms of this License in conveying all material for which you do 158 + not control copyright. Those thus making or running the covered works 159 + for you must do so exclusively on your behalf, under your direction 160 + and control, on terms that prohibit them from making any copies of 161 + your copyrighted material outside their relationship with you. 162 + 163 + Conveying under any other circumstances is permitted solely under 164 + the conditions stated below. Sublicensing is not allowed; section 10 165 + makes it unnecessary. 166 + 167 + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 + 169 + No covered work shall be deemed part of an effective technological 170 + measure under any applicable law fulfilling obligations under article 171 + 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 + similar laws prohibiting or restricting circumvention of such 173 + measures. 174 + 175 + When you convey a covered work, you waive any legal power to forbid 176 + circumvention of technological measures to the extent such circumvention 177 + is effected by exercising rights under this License with respect to 178 + the covered work, and you disclaim any intention to limit operation or 179 + modification of the work as a means of enforcing, against the work's 180 + users, your or third parties' legal rights to forbid circumvention of 181 + technological measures. 182 + 183 + 4. Conveying Verbatim Copies. 184 + 185 + You may convey verbatim copies of the Program's source code as you 186 + receive it, in any medium, provided that you conspicuously and 187 + appropriately publish on each copy an appropriate copyright notice; 188 + keep intact all notices stating that this License and any 189 + non-permissive terms added in accord with section 7 apply to the code; 190 + keep intact all notices of the absence of any warranty; and give all 191 + recipients a copy of this License along with the Program. 192 + 193 + You may charge any price or no price for each copy that you convey, 194 + and you may offer support or warranty protection for a fee. 195 + 196 + 5. Conveying Modified Source Versions. 197 + 198 + You may convey a work based on the Program, or the modifications to 199 + produce it from the Program, in the form of source code under the 200 + terms of section 4, provided that you also meet all of these conditions: 201 + 202 + a) The work must carry prominent notices stating that you modified 203 + it, and giving a relevant date. 204 + 205 + b) The work must carry prominent notices stating that it is 206 + released under this License and any conditions added under section 207 + 7. This requirement modifies the requirement in section 4 to 208 + "keep intact all notices". 209 + 210 + c) You must license the entire work, as a whole, under this 211 + License to anyone who comes into possession of a copy. This 212 + License will therefore apply, along with any applicable section 7 213 + additional terms, to the whole of the work, and all its parts, 214 + regardless of how they are packaged. This License gives no 215 + permission to license the work in any other way, but it does not 216 + invalidate such permission if you have separately received it. 217 + 218 + d) If the work has interactive user interfaces, each must display 219 + Appropriate Legal Notices; however, if the Program has interactive 220 + interfaces that do not display Appropriate Legal Notices, your 221 + work need not make them do so. 222 + 223 + A compilation of a covered work with other separate and independent 224 + works, which are not by their nature extensions of the covered work, 225 + and which are not combined with it such as to form a larger program, 226 + in or on a volume of a storage or distribution medium, is called an 227 + "aggregate" if the compilation and its resulting copyright are not 228 + used to limit the access or legal rights of the compilation's users 229 + beyond what the individual works permit. Inclusion of a covered work 230 + in an aggregate does not cause this License to apply to the other 231 + parts of the aggregate. 232 + 233 + 6. Conveying Non-Source Forms. 234 + 235 + You may convey a covered work in object code form under the terms 236 + of sections 4 and 5, provided that you also convey the 237 + machine-readable Corresponding Source under the terms of this License, 238 + in one of these ways: 239 + 240 + a) Convey the object code in, or embodied in, a physical product 241 + (including a physical distribution medium), accompanied by the 242 + Corresponding Source fixed on a durable physical medium 243 + customarily used for software interchange. 244 + 245 + b) Convey the object code in, or embodied in, a physical product 246 + (including a physical distribution medium), accompanied by a 247 + written offer, valid for at least three years and valid for as 248 + long as you offer spare parts or customer support for that product 249 + model, to give anyone who possesses the object code either (1) a 250 + copy of the Corresponding Source for all the software in the 251 + product that is covered by this License, on a durable physical 252 + medium customarily used for software interchange, for a price no 253 + more than your reasonable cost of physically performing this 254 + conveying of source, or (2) access to copy the 255 + Corresponding Source from a network server at no charge. 256 + 257 + c) Convey individual copies of the object code with a copy of the 258 + written offer to provide the Corresponding Source. This 259 + alternative is allowed only occasionally and noncommercially, and 260 + only if you received the object code with such an offer, in accord 261 + with subsection 6b. 262 + 263 + d) Convey the object code by offering access from a designated 264 + place (gratis or for a charge), and offer equivalent access to the 265 + Corresponding Source in the same way through the same place at no 266 + further charge. You need not require recipients to copy the 267 + Corresponding Source along with the object code. If the place to 268 + copy the object code is a network server, the Corresponding Source 269 + may be on a different server (operated by you or a third party) 270 + that supports equivalent copying facilities, provided you maintain 271 + clear directions next to the object code saying where to find the 272 + Corresponding Source. Regardless of what server hosts the 273 + Corresponding Source, you remain obligated to ensure that it is 274 + available for as long as needed to satisfy these requirements. 275 + 276 + e) Convey the object code using peer-to-peer transmission, provided 277 + you inform other peers where the object code and Corresponding 278 + Source of the work are being offered to the general public at no 279 + charge under subsection 6d. 280 + 281 + A separable portion of the object code, whose source code is excluded 282 + from the Corresponding Source as a System Library, need not be 283 + included in conveying the object code work. 284 + 285 + A "User Product" is either (1) a "consumer product", which means any 286 + tangible personal property which is normally used for personal, family, 287 + or household purposes, or (2) anything designed or sold for incorporation 288 + into a dwelling. In determining whether a product is a consumer product, 289 + doubtful cases shall be resolved in favor of coverage. For a particular 290 + product received by a particular user, "normally used" refers to a 291 + typical or common use of that class of product, regardless of the status 292 + of the particular user or of the way in which the particular user 293 + actually uses, or expects or is expected to use, the product. A product 294 + is a consumer product regardless of whether the product has substantial 295 + commercial, industrial or non-consumer uses, unless such uses represent 296 + the only significant mode of use of the product. 297 + 298 + "Installation Information" for a User Product means any methods, 299 + procedures, authorization keys, or other information required to install 300 + and execute modified versions of a covered work in that User Product from 301 + a modified version of its Corresponding Source. The information must 302 + suffice to ensure that the continued functioning of the modified object 303 + code is in no case prevented or interfered with solely because 304 + modification has been made. 305 + 306 + If you convey an object code work under this section in, or with, or 307 + specifically for use in, a User Product, and the conveying occurs as 308 + part of a transaction in which the right of possession and use of the 309 + User Product is transferred to the recipient in perpetuity or for a 310 + fixed term (regardless of how the transaction is characterized), the 311 + Corresponding Source conveyed under this section must be accompanied 312 + by the Installation Information. But this requirement does not apply 313 + if neither you nor any third party retains the ability to install 314 + modified object code on the User Product (for example, the work has 315 + been installed in ROM). 316 + 317 + The requirement to provide Installation Information does not include a 318 + requirement to continue to provide support service, warranty, or updates 319 + for a work that has been modified or installed by the recipient, or for 320 + the User Product in which it has been modified or installed. Access to a 321 + network may be denied when the modification itself materially and 322 + adversely affects the operation of the network or violates the rules and 323 + protocols for communication across the network. 324 + 325 + Corresponding Source conveyed, and Installation Information provided, 326 + in accord with this section must be in a format that is publicly 327 + documented (and with an implementation available to the public in 328 + source code form), and must require no special password or key for 329 + unpacking, reading or copying. 330 + 331 + 7. Additional Terms. 332 + 333 + "Additional permissions" are terms that supplement the terms of this 334 + License by making exceptions from one or more of its conditions. 335 + Additional permissions that are applicable to the entire Program shall 336 + be treated as though they were included in this License, to the extent 337 + that they are valid under applicable law. If additional permissions 338 + apply only to part of the Program, that part may be used separately 339 + under those permissions, but the entire Program remains governed by 340 + this License without regard to the additional permissions. 341 + 342 + When you convey a copy of a covered work, you may at your option 343 + remove any additional permissions from that copy, or from any part of 344 + it. (Additional permissions may be written to require their own 345 + removal in certain cases when you modify the work.) You may place 346 + additional permissions on material, added by you to a covered work, 347 + for which you have or can give appropriate copyright permission. 348 + 349 + Notwithstanding any other provision of this License, for material you 350 + add to a covered work, you may (if authorized by the copyright holders of 351 + that material) supplement the terms of this License with terms: 352 + 353 + a) Disclaiming warranty or limiting liability differently from the 354 + terms of sections 15 and 16 of this License; or 355 + 356 + b) Requiring preservation of specified reasonable legal notices or 357 + author attributions in that material or in the Appropriate Legal 358 + Notices displayed by works containing it; or 359 + 360 + c) Prohibiting misrepresentation of the origin of that material, or 361 + requiring that modified versions of such material be marked in 362 + reasonable ways as different from the original version; or 363 + 364 + d) Limiting the use for publicity purposes of names of licensors or 365 + authors of the material; or 366 + 367 + e) Declining to grant rights under trademark law for use of some 368 + trade names, trademarks, or service marks; or 369 + 370 + f) Requiring indemnification of licensors and authors of that 371 + material by anyone who conveys the material (or modified versions of 372 + it) with contractual assumptions of liability to the recipient, for 373 + any liability that these contractual assumptions directly impose on 374 + those licensors and authors. 375 + 376 + All other non-permissive additional terms are considered "further 377 + restrictions" within the meaning of section 10. If the Program as you 378 + received it, or any part of it, contains a notice stating that it is 379 + governed by this License along with a term that is a further 380 + restriction, you may remove that term. If a license document contains 381 + a further restriction but permits relicensing or conveying under this 382 + License, you may add to a covered work material governed by the terms 383 + of that license document, provided that the further restriction does 384 + not survive such relicensing or conveying. 385 + 386 + If you add terms to a covered work in accord with this section, you 387 + must place, in the relevant source files, a statement of the 388 + additional terms that apply to those files, or a notice indicating 389 + where to find the applicable terms. 390 + 391 + Additional terms, permissive or non-permissive, may be stated in the 392 + form of a separately written license, or stated as exceptions; 393 + the above requirements apply either way. 394 + 395 + 8. Termination. 396 + 397 + You may not propagate or modify a covered work except as expressly 398 + provided under this License. Any attempt otherwise to propagate or 399 + modify it is void, and will automatically terminate your rights under 400 + this License (including any patent licenses granted under the third 401 + paragraph of section 11). 402 + 403 + However, if you cease all violation of this License, then your 404 + license from a particular copyright holder is reinstated (a) 405 + provisionally, unless and until the copyright holder explicitly and 406 + finally terminates your license, and (b) permanently, if the copyright 407 + holder fails to notify you of the violation by some reasonable means 408 + prior to 60 days after the cessation. 409 + 410 + Moreover, your license from a particular copyright holder is 411 + reinstated permanently if the copyright holder notifies you of the 412 + violation by some reasonable means, this is the first time you have 413 + received notice of violation of this License (for any work) from that 414 + copyright holder, and you cure the violation prior to 30 days after 415 + your receipt of the notice. 416 + 417 + Termination of your rights under this section does not terminate the 418 + licenses of parties who have received copies or rights from you under 419 + this License. If your rights have been terminated and not permanently 420 + reinstated, you do not qualify to receive new licenses for the same 421 + material under section 10. 422 + 423 + 9. Acceptance Not Required for Having Copies. 424 + 425 + You are not required to accept this License in order to receive or 426 + run a copy of the Program. Ancillary propagation of a covered work 427 + occurring solely as a consequence of using peer-to-peer transmission 428 + to receive a copy likewise does not require acceptance. However, 429 + nothing other than this License grants you permission to propagate or 430 + modify any covered work. These actions infringe copyright if you do 431 + not accept this License. Therefore, by modifying or propagating a 432 + covered work, you indicate your acceptance of this License to do so. 433 + 434 + 10. Automatic Licensing of Downstream Recipients. 435 + 436 + Each time you convey a covered work, the recipient automatically 437 + receives a license from the original licensors, to run, modify and 438 + propagate that work, subject to this License. You are not responsible 439 + for enforcing compliance by third parties with this License. 440 + 441 + An "entity transaction" is a transaction transferring control of an 442 + organization, or substantially all assets of one, or subdividing an 443 + organization, or merging organizations. If propagation of a covered 444 + work results from an entity transaction, each party to that 445 + transaction who receives a copy of the work also receives whatever 446 + licenses to the work the party's predecessor in interest had or could 447 + give under the previous paragraph, plus a right to possession of the 448 + Corresponding Source of the work from the predecessor in interest, if 449 + the predecessor has it or can get it with reasonable efforts. 450 + 451 + You may not impose any further restrictions on the exercise of the 452 + rights granted or affirmed under this License. For example, you may 453 + not impose a license fee, royalty, or other charge for exercise of 454 + rights granted under this License, and you may not initiate litigation 455 + (including a cross-claim or counterclaim in a lawsuit) alleging that 456 + any patent claim is infringed by making, using, selling, offering for 457 + sale, or importing the Program or any portion of it. 458 + 459 + 11. Patents. 460 + 461 + A "contributor" is a copyright holder who authorizes use under this 462 + License of the Program or a work on which the Program is based. The 463 + work thus licensed is called the contributor's "contributor version". 464 + 465 + A contributor's "essential patent claims" are all patent claims 466 + owned or controlled by the contributor, whether already acquired or 467 + hereafter acquired, that would be infringed by some manner, permitted 468 + by this License, of making, using, or selling its contributor version, 469 + but do not include claims that would be infringed only as a 470 + consequence of further modification of the contributor version. For 471 + purposes of this definition, "control" includes the right to grant 472 + patent sublicenses in a manner consistent with the requirements of 473 + this License. 474 + 475 + Each contributor grants you a non-exclusive, worldwide, royalty-free 476 + patent license under the contributor's essential patent claims, to 477 + make, use, sell, offer for sale, import and otherwise run, modify and 478 + propagate the contents of its contributor version. 479 + 480 + In the following three paragraphs, a "patent license" is any express 481 + agreement or commitment, however denominated, not to enforce a patent 482 + (such as an express permission to practice a patent or covenant not to 483 + sue for patent infringement). To "grant" such a patent license to a 484 + party means to make such an agreement or commitment not to enforce a 485 + patent against the party. 486 + 487 + If you convey a covered work, knowingly relying on a patent license, 488 + and the Corresponding Source of the work is not available for anyone 489 + to copy, free of charge and under the terms of this License, through a 490 + publicly available network server or other readily accessible means, 491 + then you must either (1) cause the Corresponding Source to be so 492 + available, or (2) arrange to deprive yourself of the benefit of the 493 + patent license for this particular work, or (3) arrange, in a manner 494 + consistent with the requirements of this License, to extend the patent 495 + license to downstream recipients. "Knowingly relying" means you have 496 + actual knowledge that, but for the patent license, your conveying the 497 + covered work in a country, or your recipient's use of the covered work 498 + in a country, would infringe one or more identifiable patents in that 499 + country that you have reason to believe are valid. 500 + 501 + If, pursuant to or in connection with a single transaction or 502 + arrangement, you convey, or propagate by procuring conveyance of, a 503 + covered work, and grant a patent license to some of the parties 504 + receiving the covered work authorizing them to use, propagate, modify 505 + or convey a specific copy of the covered work, then the patent license 506 + you grant is automatically extended to all recipients of the covered 507 + work and works based on it. 508 + 509 + A patent license is "discriminatory" if it does not include within 510 + the scope of its coverage, prohibits the exercise of, or is 511 + conditioned on the non-exercise of one or more of the rights that are 512 + specifically granted under this License. You may not convey a covered 513 + work if you are a party to an arrangement with a third party that is 514 + in the business of distributing software, under which you make payment 515 + to the third party based on the extent of your activity of conveying 516 + the work, and under which the third party grants, to any of the 517 + parties who would receive the covered work from you, a discriminatory 518 + patent license (a) in connection with copies of the covered work 519 + conveyed by you (or copies made from those copies), or (b) primarily 520 + for and in connection with specific products or compilations that 521 + contain the covered work, unless you entered into that arrangement, 522 + or that patent license was granted, prior to 28 March 2007. 523 + 524 + Nothing in this License shall be construed as excluding or limiting 525 + any implied license or other defenses to infringement that may 526 + otherwise be available to you under applicable patent law. 527 + 528 + 12. No Surrender of Others' Freedom. 529 + 530 + If conditions are imposed on you (whether by court order, agreement or 531 + otherwise) that contradict the conditions of this License, they do not 532 + excuse you from the conditions of this License. If you cannot convey a 533 + covered work so as to satisfy simultaneously your obligations under this 534 + License and any other pertinent obligations, then as a consequence you may 535 + not convey it at all. For example, if you agree to terms that obligate you 536 + to collect a royalty for further conveying from those to whom you convey 537 + the Program, the only way you could satisfy both those terms and this 538 + License would be to refrain entirely from conveying the Program. 539 + 540 + 13. Remote Network Interaction; Use with the GNU General Public License. 541 + 542 + Notwithstanding any other provision of this License, if you modify the 543 + Program, your modified version must prominently offer all users 544 + interacting with it remotely through a computer network (if your version 545 + supports such interaction) an opportunity to receive the Corresponding 546 + Source of your version by providing access to the Corresponding Source 547 + from a network server at no charge, through some standard or customary 548 + means of facilitating copying of software. This Corresponding Source 549 + shall include the Corresponding Source for any work covered by version 3 550 + of the GNU General Public License that is incorporated pursuant to the 551 + following paragraph. 552 + 553 + Notwithstanding any other provision of this License, you have 554 + permission to link or combine any covered work with a work licensed 555 + under version 3 of the GNU General Public License into a single 556 + combined work, and to convey the resulting work. The terms of this 557 + License will continue to apply to the part which is the covered work, 558 + but the work with which it is combined will remain governed by version 559 + 3 of the GNU General Public License. 560 + 561 + 14. Revised Versions of this License. 562 + 563 + The Free Software Foundation may publish revised and/or new versions of 564 + the GNU Affero General Public License from time to time. Such new versions 565 + will be similar in spirit to the present version, but may differ in detail to 566 + address new problems or concerns. 567 + 568 + Each version is given a distinguishing version number. If the 569 + Program specifies that a certain numbered version of the GNU Affero General 570 + Public License "or any later version" applies to it, you have the 571 + option of following the terms and conditions either of that numbered 572 + version or of any later version published by the Free Software 573 + Foundation. If the Program does not specify a version number of the 574 + GNU Affero General Public License, you may choose any version ever published 575 + by the Free Software Foundation. 576 + 577 + If the Program specifies that a proxy can decide which future 578 + versions of the GNU Affero General Public License can be used, that proxy's 579 + public statement of acceptance of a version permanently authorizes you 580 + to choose that version for the Program. 581 + 582 + Later license versions may give you additional or different 583 + permissions. However, no additional obligations are imposed on any 584 + author or copyright holder as a result of your choosing to follow a 585 + later version. 586 + 587 + 15. Disclaimer of Warranty. 588 + 589 + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 + APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 + HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 + OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 + PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 + IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 + ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 + 598 + 16. Limitation of Liability. 599 + 600 + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 + THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 + GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 + USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 + DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 + PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 + EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 + SUCH DAMAGES. 609 + 610 + 17. Interpretation of Sections 15 and 16. 611 + 612 + If the disclaimer of warranty and limitation of liability provided 613 + above cannot be given local legal effect according to their terms, 614 + reviewing courts shall apply local law that most closely approximates 615 + an absolute waiver of all civil liability in connection with the 616 + Program, unless a warranty or assumption of liability accompanies a 617 + copy of the Program in return for a fee. 618 + 619 + END OF TERMS AND CONDITIONS 620 + 621 + How to Apply These Terms to Your New Programs 622 + 623 + If you develop a new program, and you want it to be of the greatest 624 + possible use to the public, the best way to achieve this is to make it 625 + free software which everyone can redistribute and change under these terms. 626 + 627 + To do so, attach the following notices to the program. It is safest 628 + to attach them to the start of each source file to most effectively 629 + state the exclusion of warranty; and each file should have at least 630 + the "copyright" line and a pointer to where the full notice is found. 631 + 632 + <one line to give the program's name and a brief idea of what it does.> 633 + Copyright (C) <year> <name of author> 634 + 635 + This program is free software: you can redistribute it and/or modify 636 + it under the terms of the GNU Affero General Public License as published by 637 + the Free Software Foundation, either version 3 of the License, or 638 + (at your option) any later version. 639 + 640 + This program is distributed in the hope that it will be useful, 641 + but WITHOUT ANY WARRANTY; without even the implied warranty of 642 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 + GNU Affero General Public License for more details. 644 + 645 + You should have received a copy of the GNU Affero General Public License 646 + along with this program. If not, see <http://www.gnu.org/licenses/>. 647 + 648 + Also add information on how to contact you by electronic and paper mail. 649 + 650 + If your software can interact with users remotely through a computer 651 + network, you should also make sure that it provides a way for users to 652 + get its source. For example, if your program is a web application, its 653 + interface could display a "Source" link that leads users to an archive 654 + of the code. There are many ways you could offer source, and different 655 + solutions will be better for different programs; see section 13 for the 656 + specific requirements. 657 + 658 + You should also get your employer (if you work as a programmer) or school, 659 + if any, to sign a "copyright disclaimer" for the program, if necessary. 660 + For more information on this, and how to apply and follow the GNU AGPL, see 661 + <http://www.gnu.org/licenses/>.
+11
Gemfile
··· 1 + # frozen_string_literal: true 2 + 3 + source "https://rubygems.org" 4 + gem "amazing_print" 5 + gem "blather", git: "https://github.com/adhearsion/blather.git", branch: "develop" 6 + gem "em-http-request", git: "https://github.com/singpolyma/em-http-request", branch: "fix-letsencrypt" 7 + gem "em_promise.rb" 8 + gem "ougai" 9 + gem "savon" 10 + 11 + gem "rubocop"
+84
lib/addresses.rb
··· 1 + # frozen_string_literal: true 2 + 3 + class Addresses < Blather::XMPPNode 4 + include Enumerable 5 + register :addresses, "http://jabber.org/protocol/address" 6 + 7 + def self.new(addresses) 8 + new_node = super :addresses 9 + 10 + if addresses.is_a?(Array) 11 + addresses.each do |address| 12 + new_node << Address.new(**address) 13 + end 14 + end 15 + 16 + new_node 17 + end 18 + 19 + def self.import(node) 20 + ns = node.namespace&.href 21 + klass = class_from_registration(node.element_name, ns) 22 + # For some reason blather tries to import a message with us as a child as us 23 + # So if we don't override this it leads to infinite recursion 24 + if klass == Blather::Stanza::Message 25 + Blather::Stanza::Message.new(node[:type]).inherit(node) 26 + else 27 + super 28 + end 29 + end 30 + 31 + def each 32 + find("./ns:address", ns: self.class.registered_ns).each do |node| 33 + yield Address.import(node) 34 + end 35 + end 36 + 37 + class Address < Blather::XMPPNode 38 + register :address, "http://jabber.org/protocol/address" 39 + 40 + def self.new(*, type: nil, jid: nil, uri: nil, delivered: nil) 41 + new_node = super :address 42 + new_node["type"] = type 43 + new_node["jid"] = jid if jid 44 + new_node["uri"] = uri if uri 45 + new_node["delivered"] = delivered.to_s unless delivered.nil? 46 + new_node 47 + end 48 + 49 + def type 50 + self["type"] 51 + end 52 + 53 + def jid 54 + if self["jid"] 55 + Blather::JID.new(self["jid"]) 56 + else 57 + Blather::JID.new(uri.sub(/\Asms:\+?/, ""), "mms.chat.1pcom.net") 58 + end 59 + end 60 + 61 + def uri 62 + self["uri"] 63 + end 64 + 65 + def delivered? 66 + self["delivered"] == "true" 67 + end 68 + end 69 + end 70 + 71 + module Blather 72 + class Stanza 73 + class Message 74 + def addresses 75 + find( 76 + "/message/ns:addresses", 77 + ns: "http://jabber.org/protocol/address" 78 + ).first&.then do |node| 79 + Addresses.import(node) 80 + end 81 + end 82 + end 83 + end 84 + end
+73
lib/blather_client.rb
··· 1 + # frozen_string_literal: true 2 + 3 + class BlatherClient < Blather::Client 4 + def handle_data(stanza) 5 + EMPromise.resolve(nil).then { 6 + with_sentry(stanza) do |scope| 7 + Thread.current[:log] = ::LOG.child( 8 + transaction: scope.transaction_name 9 + ) 10 + super 11 + rescue StandardError => e 12 + handle_error(scope, stanza, e) 13 + end 14 + }.catch { |e| panic(e) } 15 + end 16 + 17 + def with_sentry(stanza) 18 + Sentry.clone_hub_to_current_thread 19 + 20 + Sentry.with_scope do |scope| 21 + setup_scope(stanza, scope) 22 + yield scope 23 + ensure 24 + scope.get_transaction&.then do |tx| 25 + tx.set_status("ok") unless tx.status 26 + tx.finish 27 + end 28 + end 29 + end 30 + 31 + def setup_scope(stanza, scope) 32 + name = stanza.respond_to?(:node) ? stanza.node : stanza.name 33 + scope.clear_breadcrumbs 34 + scope.set_transaction_name(name) 35 + scope.set_user(jid: stanza.from.stripped.to_s) 36 + 37 + transaction = Sentry.start_transaction( 38 + name: name, 39 + op: "blather.handle_data" 40 + ) 41 + scope.set_span(transaction) if transaction 42 + end 43 + 44 + def handle_error(scope, stanza, e) 45 + log.error( 46 + "Error raised during #{scope.transaction_name}: " \ 47 + "#{e.class}", 48 + e 49 + ) 50 + Sentry.capture_exception(e) unless e.is_a?(Sentry::Error) 51 + scope.get_transaction&.set_status("internal_error") 52 + return if e.respond_to?(:replied?) && e.replied? 53 + 54 + write stanza.as_error("internal-server-error", :cancel) 55 + end 56 + 57 + def call_handler(handler, guards, stanza) 58 + result = if guards.first.respond_to?(:to_str) 59 + found = stanza.find(*guards) 60 + throw :pass if found.empty? 61 + 62 + handler.call(stanza, found) 63 + else 64 + throw :pass if guarded?(guards, stanza) 65 + 66 + handler.call(stanza) 67 + end 68 + 69 + return result unless result.is_a?(Promise) 70 + 71 + result.sync 72 + end 73 + end
+9
lib/blather_ext.rb
··· 1 + # frozen_string_literal: true 2 + 3 + module Blather 4 + class JID 5 + def with(node: self.node, domain: self.domain, resource: self.resource) 6 + self.class.new(node, domain, resource) 7 + end 8 + end 9 + end
+23
lib/em.rb
··· 1 + # frozen_string_literal: true 2 + 3 + require "em_promise" 4 + 5 + module EM 6 + def self.promise_defer(klass: EMPromise, &block) 7 + promise = klass.new 8 + EventMachine.defer( 9 + block, 10 + promise.method(:fulfill), 11 + promise.method(:reject) 12 + ) 13 + promise 14 + end 15 + 16 + def self.promise_timer(timeout) 17 + promise = EMPromise.new 18 + EM.add_timer(timeout) do 19 + promise.fulfill(nil) 20 + end 21 + promise 22 + end 23 + end
+64
lib/incoming_mms.rb
··· 1 + # frozen_string_literal: true 2 + 3 + class IncomingMMS 4 + def self.for(to, json) 5 + raise "Unknown encoding: #{json.inspect}" if json["encoding"] != "native" 6 + 7 + txt, media = extract_parts(json) 8 + 9 + EMPromise.all( 10 + txt.map { |u| 11 + EM::HttpRequest.new(u, tls: { verify_peer: true }).get.then(&:response) 12 + } 13 + ).then do |fetched_txt| 14 + new(to, fetched_txt, media, clean_fake_array(json["recip"])) 15 + end 16 + end 17 + 18 + def self.extract_parts(json) 19 + clean_fake_array(json["files"]) 20 + .grep_v(/\.smil\Z/i) 21 + .map { |part| "#{json['url']}&authkey=#{json['authkey']}&file=#{part}" } 22 + .partition { |url| url.end_with?(".txt") } 23 + end 24 + 25 + def self.clean_fake_array(str) 26 + # Instead of arrays we get sent comma-seperated strings 27 + # which sometimes contain blank elements or random whitespace 28 + str.to_s.split(",").map(&:strip).reject(&:empty?) 29 + end 30 + 31 + def initialize(to, txt, media, recip) 32 + @to = to 33 + @txt = txt 34 + @media = media 35 + @recip = recip 36 + end 37 + 38 + def unproxied_to 39 + ProxiedJID.new(@to).unproxied 40 + end 41 + 42 + def oobs 43 + @media.map(&OOB.method(:new)) 44 + end 45 + 46 + def addresses 47 + return nil if @recip.empty? 48 + 49 + @addresses ||= Addresses.new( 50 + [{ type: "to", jid: unproxied_to }] + 51 + @recip.map { |r| { type: "to", uri: "sms:+#{r}", delivered: true } } 52 + ) 53 + end 54 + 55 + def to_stanza 56 + Blather::Stanza::Message.new( 57 + addresses ? unproxied_to.domain : unproxied_to, 58 + @txt.empty? ? nil : @txt.join("\n\n") 59 + ).tap do |m| 60 + oobs.each { |oob| m << oob } 61 + m << addresses if addresses 62 + end 63 + end 64 + end
+66
lib/oob.rb
··· 1 + # frozen_string_literal: true 2 + 3 + require "blather" 4 + 5 + class OOB < Blather::XMPPNode 6 + register :oob, "jabber:x:oob" 7 + 8 + def self.new(url=nil, desc: nil) 9 + new_node = super :x 10 + 11 + case url 12 + when Nokogiri::XML::Node 13 + new_node.inherit url 14 + else 15 + new_node.url = url if url && url != "x" && url != :x 16 + new_node.desc = desc if desc 17 + end 18 + 19 + new_node 20 + end 21 + 22 + def self.find_or_create(parent) 23 + if (found_x = parent.find("ns:x", ns: registered_ns).first) 24 + x = new(found_x) 25 + found_x.remove 26 + else 27 + x = new 28 + end 29 + parent << x 30 + x 31 + end 32 + 33 + def url 34 + find("ns:url", ns: self.class.registered_ns).first&.content 35 + end 36 + 37 + def url=(url) 38 + remove_children :url 39 + i = Niceogiri::XML::Node.new(:url, document, namespace) 40 + i.content = url 41 + self << i 42 + end 43 + 44 + def desc 45 + find("ns:desc", ns: self.class.registered_ns).first&.content 46 + end 47 + 48 + def desc=(description) 49 + remove_children :desc 50 + i = Niceogiri::XML::Node.new(:desc, document, namespace) 51 + i.content = description 52 + self << i 53 + end 54 + end 55 + 56 + module Blather 57 + class Stanza 58 + class Message 59 + def oobs 60 + find("/message/ns:x", ns: "jabber:x:oob").map do |node| 61 + OOB.import(node) 62 + end 63 + end 64 + end 65 + end 66 + end
+42
lib/outgoing_mms.rb
··· 1 + # frozen_string_literal: true 2 + 3 + class OutgoingMMS 4 + def self.for(m) 5 + body = m.body.sub(m.oobs.first.url, "") 6 + OutgoingMMS.new( 7 + addresses: m.addresses || 8 + [Addresses::Address.new(uri: "sms:#{m.to.node}")], 9 + body: body, 10 + urls: m.oobs&.map(&:url) 11 + ) 12 + end 13 + 14 + def initialize(addresses:, body: nil, urls: nil) 15 + @addresses = addresses.to_a 16 + @to = @addresses.pop 17 + @body = body 18 + @urls = urls 19 + end 20 + 21 + def as_json(*) 22 + { 23 + encoding: :native, 24 + recip: @addresses.map { |adr| adr.uri.sub(/\Asms:\+?/, "") }.join(",") 25 + } 26 + .merge(@urls ? { files: @urls.join(",") } : {}) 27 + .merge(@body && !@body.empty? ? { textmessagebody: @body } : {}) 28 + end 29 + 30 + def to_json(*) 31 + as_json.to_json 32 + end 33 + 34 + def to_stanza(id:, from:) 35 + Blather::Stanza::Message.new(@to.jid, to_json).tap do |m| 36 + m.id = id 37 + m.from = 38 + ProxiedJID.proxy(from, CONFIG[:component][:jid]) 39 + .with(resource: "#{from.resource}/#{m.id}") 40 + end 41 + end 42 + end
+28
lib/proxied_jid.rb
··· 1 + # frozen_string_literal: true 2 + 3 + require "delegate" 4 + require "blather" 5 + 6 + class ProxiedJID < SimpleDelegator 7 + ESCAPED = /20|22|26|27|2f|3a|3c|3e|40|5c/.freeze 8 + 9 + def unproxied 10 + Blather::JID.new( 11 + node&.gsub(/\\(#{ESCAPED})/) { |s| 12 + s[1..-1].to_i(16).chr 13 + } 14 + ) 15 + end 16 + 17 + def self.proxy(jid, suffix) 18 + jid = Blather::JID.new(jid) 19 + ProxiedJID.new(Blather::JID.new( 20 + jid.stripped.to_s 21 + .gsub(/([ "&'\/:<>@]|\\(?=#{ESCAPED}))/) { |s| 22 + "\\#{s.ord.to_s(16)}" 23 + }, 24 + suffix, 25 + jid.resource 26 + )) 27 + end 28 + end
+54
lib/registration_repo.rb
··· 1 + # frozen_string_literal: true 2 + 3 + require "savon" 4 + 5 + class RegistrationRepo 6 + def initialize(redis:) 7 + @redis = redis 8 + @savon = Savon.client { 9 + wsdl "https://api.1pcom.net/ws2/DIDManagement.asmx?WSDL" 10 + convert_request_keys_to :camelcase 11 + } 12 + end 13 + 14 + def find(jid) 15 + @redis.lrange("endstream_registration-#{jid.stripped}", 0, 2) 16 + end 17 + 18 + def put(jid, *creds) 19 + setup_endstream_route(*creds, jid).then do |status| 20 + next status unless status.first[:code].to_i.zero? 21 + 22 + @redis.rpush( 23 + "endstream_registration-#{jid.stripped}", 24 + *creds 25 + ).then { status } 26 + end 27 + end 28 + 29 + def delete(jid) 30 + find(jid).then do |creds| 31 + next { code: 0 } unless creds 32 + 33 + EMPromise.all([ 34 + setup_endstream_route(*creds, "#{creds.first}@example.com"), 35 + @redis.del("endstream_registration-#{jid.stripped}") 36 + ]).then { |(status, _)| status } 37 + end 38 + end 39 + 40 + protected 41 + 42 + def setup_endstream_route(tel, username, password, jid) 43 + EM.promise_defer { 44 + @savon.call( 45 + :did_route_sms_to_xmpp, message: { 46 + auth: { username: username, password: password }, 47 + dID: tel.sub(/\A\+/, ""), 48 + xMPP_user: 49 + ProxiedJID.proxy(jid, CONFIG[:component][:jid]).stripped.to_s 50 + } 51 + ).body.dig(:did_route_sms_to_xmpp_response, :did_route_sms_to_xmpp_result) 52 + } 53 + end 54 + end
+222
sgx_endstream.rb
··· 1 + #!/usr/bin/ruby 2 + # frozen_string_literal: true 3 + 4 + require "blather/client/dsl" 5 + require "dhall" 6 + require "em-hiredis" 7 + require "em-http" 8 + require "em_promise" 9 + require "json" 10 + require "ougai" 11 + require "sentry-ruby" 12 + 13 + require_relative "lib/blather_client" 14 + require_relative "lib/blather_ext" 15 + require_relative "lib/em" 16 + require_relative "lib/incoming_mms" 17 + require_relative "lib/oob" 18 + require_relative "lib/outgoing_mms" 19 + require_relative "lib/proxied_jid" 20 + require_relative "lib/registration_repo" 21 + 22 + singleton_class.class_eval do 23 + include Blather::DSL 24 + Blather::DSL.append_features(self) 25 + end 26 + 27 + $stdout.sync = true 28 + LOG = Ougai::Logger.new($stdout) 29 + LOG.level = ENV.fetch("LOG_LEVEL", "info") 30 + LOG.formatter = Ougai::Formatters::Readable.new( 31 + nil, 32 + nil, 33 + plain: !$stdout.isatty 34 + ) 35 + Blather.logger = LOG 36 + 37 + def log 38 + Thread.current[:log] || LOG 39 + end 40 + 41 + Sentry.init do |config| 42 + config.logger = LOG 43 + config.breadcrumbs_logger = [:sentry_logger] 44 + end 45 + 46 + CONFIG = Dhall::Coder 47 + .new(safe: Dhall::Coder::JSON_LIKE + [Symbol, Proc]) 48 + .load( 49 + "(#{ARGV[0]}) : #{__dir__}/config-schema.dhall", 50 + transform_keys: ->(k) { k&.to_sym } 51 + ) 52 + 53 + def panic(e, hub=nil) 54 + log.fatal( 55 + "Error raised during event loop: #{e.class}", 56 + e 57 + ) 58 + if e.is_a?(::Exception) 59 + (hub || Sentry).capture_exception(e, hint: { background: false }) 60 + else 61 + (hub || Sentry).capture_message(e.to_s, hint: { background: false }) 62 + end 63 + exit 1 64 + end 65 + 66 + EM.error_handler(&method(:panic)) 67 + 68 + @client = BlatherClient.new 69 + 70 + setup( 71 + CONFIG[:component][:jid], 72 + CONFIG[:component][:secret], 73 + CONFIG[:server][:host], 74 + CONFIG[:server][:port], 75 + nil, 76 + nil, 77 + async: true 78 + ) 79 + 80 + when_ready do 81 + log.info "Ready" 82 + REDIS = EM::Hiredis.connect 83 + REGISTRATION_REPO = RegistrationRepo.new(redis: REDIS) 84 + end 85 + 86 + disco_info to: Blather::JID.new(CONFIG[:component][:jid]) do |iq| 87 + reply = iq.reply 88 + reply.identities = [{ 89 + name: "SGX Endstream", 90 + type: "sms", 91 + category: "gateway" 92 + }] 93 + reply.features = [ 94 + "http://jabber.org/protocol/disco#info", 95 + "http://jabber.org/protocol/address", 96 + "jabber:iq:register" 97 + ] 98 + self << reply 99 + end 100 + 101 + disco_info to: /\A\+?\d+@/ do |iq| 102 + reply = iq.reply 103 + reply.identities = [{ 104 + name: "SGX Endstream", 105 + type: "sms", 106 + category: "client" 107 + }] 108 + reply.features = [ 109 + "urn:xmpp:receipts" 110 + ] 111 + self << reply 112 + end 113 + 114 + ibr type: :get do |iq| 115 + REDIS.lrange( 116 + "endstream_registration-#{iq.from.stripped}", 0, 2 117 + ).then do |creds| 118 + reply = iq.reply 119 + reply.registered = true if creds&.first 120 + reply.phone = creds&.first.to_s 121 + reply.username = "" 122 + reply.password = "" 123 + self << reply 124 + end 125 + end 126 + 127 + ibr type: :set do |iq| 128 + if iq.phone.to_s !~ /\A\+?1\d{10}\Z/ 129 + self << iq.as_error("bad-request", :modify, "Invalid phone number") 130 + next 131 + end 132 + 133 + if iq.username.to_s.empty? || iq.password.to_s.empty? 134 + self << iq.as_error( 135 + "bad-request", 136 + :modify, 137 + "Username and password are required" 138 + ) 139 + next 140 + end 141 + 142 + REGISTRATION_REPO.delete(iq.from).then { |status| 143 + next status if !status[:code].to_i.zero? || iq.remove? 144 + 145 + REGISTRATION_REPO.put(iq.from, iq.phone, iq.username, iq.password) 146 + }.then { |status| 147 + self << if status[:code].to_i.zero? 148 + iq.reply 149 + else 150 + iq.as_error("bad-request", :modify, r[:text]) 151 + end 152 + } 153 + end 154 + 155 + message from: /@sms.chat.1pcom.net\Z/ do |m| 156 + tel = if m.from.node.length > 7 157 + "+{m.from.node}" 158 + else 159 + "#{m.from.node};phone-context=ca-us.phone-context.soprani.ca" 160 + end 161 + m.from = Blather::JID.new(tel, CONFIG[:component][:jid]) 162 + m.to = ProxiedJID.new(m.to).unproxied 163 + m.subject = nil # They send a generic subject for some reason 164 + self << m 165 + end 166 + 167 + message from: /@mms.chat.1pcom.net\Z/ do |m| 168 + json = JSON.parse(m.body) 169 + if json["GlobalStatus"] 170 + log.info("MMS Status", json["disposition"]) 171 + next 172 + end 173 + 174 + IncomingMMS.for(m.to, json).then(&:to_stanza).then { |to_send| 175 + to_send.id = m.id 176 + to_send.from = Blather::JID.new("+#{m.from.node}", CONFIG[:component][:jid]) 177 + self << to_send 178 + } 179 + end 180 + 181 + # Swallow errors, endstream doesn't want them 182 + message type: :error do 183 + true 184 + end 185 + 186 + message :addresses, to: Blather::JID.new(CONFIG[:component][:jid]) do |m| 187 + self << OutgoingMMS.for(m).to_stanza(id: m.id, from: m.from) 188 + end 189 + 190 + message ->(m) { !m.oobs.empty? }, to: /\A\+?\d+@/ do |m| 191 + # TODO: if too big or bad mime, send sms 192 + self << OutgoingMMS.for(m).to_stanza(id: m.id, from: m.from) 193 + end 194 + 195 + def too_long_for_sms(m) 196 + # ~3 segments 197 + m.body.length > (m.body.ascii_only? ? 160 : 70) * 3 198 + end 199 + 200 + message :body, method(:too_long_for_sms), to: /\A\+?\d+@/ do |m| 201 + self << OutgoingMMS.for(m).to_stanza(id: m.id, from: m.from) 202 + end 203 + 204 + message( 205 + :body, 206 + to: /(?:\A\+?\d+@)|(?:;phone-context=ca-us\.phone-context\.soprani\.ca\Z)/ 207 + ) do |m| 208 + m.to = Blather::JID.new( 209 + m.to.node.sub(/\A\+/, "").sub(/;phone-context=.*\Z/, ""), 210 + "sms.chat.1pcom.net" 211 + ) 212 + m.from = ProxiedJID.proxy(m.from, CONFIG[:component][:jid]) 213 + self << m 214 + end 215 + 216 + iq type: [:get, :set] do |iq| 217 + self << iq.as_error("service-unavailable", :cancel) 218 + end 219 + 220 + trap(:INT) { EM.stop } 221 + trap(:TERM) { EM.stop } 222 + EM.run { client.run }