diff --git a/content/docs/API/mCaptcha-system.md b/content/docs/API/mCaptcha-system.md index 973a17d..b560a0f 100644 --- a/content/docs/API/mCaptcha-system.md +++ b/content/docs/API/mCaptcha-system.md @@ -18,6 +18,7 @@ Documentation for the library used in mCaptcha core. ## Versions - [master-branch](https://mcaptcha.github.io/mCaptcha/m_captcha/index.html) -- [0.1.0](/api-docs/m_captcha/0.1.0/m_captcha/index.html) -- [0.1.1](/api-docs/m_captcha/0.1.1/m_captcha/index.html) +- [0.1.3](/api-docs/m_captcha/0.1.3/m_captcha/index.html) - [0.1.2](/api-docs/m_captcha/0.1.2/m_captcha/index.html) +- [0.1.1](/api-docs/m_captcha/0.1.1/m_captcha/index.html) +- [0.1.0](/api-docs/m_captcha/0.1.0/m_captcha/index.html) diff --git a/static/api-docs/m_captcha/0.1.3/COPYRIGHT.txt b/static/api-docs/m_captcha/0.1.3/COPYRIGHT.txt new file mode 100644 index 0000000..af77776 --- /dev/null +++ b/static/api-docs/m_captcha/0.1.3/COPYRIGHT.txt @@ -0,0 +1,45 @@ +These documentation pages include resources by third parties. This copyright +file applies only to those resources. The following third party resources are +included, and carry their own copyright notices and license terms: + +* Fira Sans (FiraSans-Regular.woff, FiraSans-Medium.woff): + + Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ + with Reserved Font Name Fira Sans. + + Copyright (c) 2014, Telefonica S.A. + + Licensed under the SIL Open Font License, Version 1.1. + See FiraSans-LICENSE.txt. + +* rustdoc.css, main.js, and playpen.js: + + Copyright 2015 The Rust Developers. + Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or + the MIT license (LICENSE-MIT.txt) at your option. + +* normalize.css: + + Copyright (c) Nicolas Gallagher and Jonathan Neal. + Licensed under the MIT license (see LICENSE-MIT.txt). + +* Source Code Pro (SourceCodePro-Regular.woff, SourceCodePro-Semibold.woff): + + Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark + of Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceCodePro-LICENSE.txt. + +* Source Serif Pro (SourceSerifPro-Regular.ttf.woff, + SourceSerifPro-Bold.ttf.woff, SourceSerifPro-It.ttf.woff): + + Copyright 2014 Adobe Systems Incorporated (http://www.adobe.com/), with + Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of + Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceSerifPro-LICENSE.txt. + +This copyright file is intended to be distributed with rustdoc output. diff --git a/static/api-docs/m_captcha/0.1.3/FiraSans-LICENSE.txt b/static/api-docs/m_captcha/0.1.3/FiraSans-LICENSE.txt new file mode 100644 index 0000000..d444ea9 --- /dev/null +++ b/static/api-docs/m_captcha/0.1.3/FiraSans-LICENSE.txt @@ -0,0 +1,94 @@ +Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A. +with Reserved Font Name < Fira >, + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/static/api-docs/m_captcha/0.1.3/FiraSans-Medium.woff b/static/api-docs/m_captcha/0.1.3/FiraSans-Medium.woff new file mode 100644 index 0000000..7d742c5 Binary files /dev/null and b/static/api-docs/m_captcha/0.1.3/FiraSans-Medium.woff differ diff --git a/static/api-docs/m_captcha/0.1.3/FiraSans-Regular.woff b/static/api-docs/m_captcha/0.1.3/FiraSans-Regular.woff new file mode 100644 index 0000000..d8e0363 Binary files /dev/null and b/static/api-docs/m_captcha/0.1.3/FiraSans-Regular.woff differ diff --git a/static/api-docs/m_captcha/0.1.3/LICENSE-APACHE.txt b/static/api-docs/m_captcha/0.1.3/LICENSE-APACHE.txt new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/static/api-docs/m_captcha/0.1.3/LICENSE-APACHE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/static/api-docs/m_captcha/0.1.3/LICENSE-MIT.txt b/static/api-docs/m_captcha/0.1.3/LICENSE-MIT.txt new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/static/api-docs/m_captcha/0.1.3/LICENSE-MIT.txt @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/static/api-docs/m_captcha/0.1.3/SourceCodePro-LICENSE.txt b/static/api-docs/m_captcha/0.1.3/SourceCodePro-LICENSE.txt new file mode 100644 index 0000000..0754257 --- /dev/null +++ b/static/api-docs/m_captcha/0.1.3/SourceCodePro-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/static/api-docs/m_captcha/0.1.3/SourceCodePro-Regular.woff b/static/api-docs/m_captcha/0.1.3/SourceCodePro-Regular.woff new file mode 100644 index 0000000..5576670 Binary files /dev/null and b/static/api-docs/m_captcha/0.1.3/SourceCodePro-Regular.woff differ diff --git a/static/api-docs/m_captcha/0.1.3/SourceCodePro-Semibold.woff b/static/api-docs/m_captcha/0.1.3/SourceCodePro-Semibold.woff new file mode 100644 index 0000000..ca972a1 Binary files /dev/null and b/static/api-docs/m_captcha/0.1.3/SourceCodePro-Semibold.woff differ diff --git a/static/api-docs/m_captcha/0.1.3/SourceSerifPro-Bold.ttf.woff b/static/api-docs/m_captcha/0.1.3/SourceSerifPro-Bold.ttf.woff new file mode 100644 index 0000000..ca25431 Binary files /dev/null and b/static/api-docs/m_captcha/0.1.3/SourceSerifPro-Bold.ttf.woff differ diff --git a/static/api-docs/m_captcha/0.1.3/SourceSerifPro-It.ttf.woff b/static/api-docs/m_captcha/0.1.3/SourceSerifPro-It.ttf.woff new file mode 100644 index 0000000..a287bbe Binary files /dev/null and b/static/api-docs/m_captcha/0.1.3/SourceSerifPro-It.ttf.woff differ diff --git a/static/api-docs/m_captcha/0.1.3/SourceSerifPro-LICENSE.md b/static/api-docs/m_captcha/0.1.3/SourceSerifPro-LICENSE.md new file mode 100644 index 0000000..22cb755 --- /dev/null +++ b/static/api-docs/m_captcha/0.1.3/SourceSerifPro-LICENSE.md @@ -0,0 +1,93 @@ +Copyright 2014-2018 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/static/api-docs/m_captcha/0.1.3/SourceSerifPro-Regular.ttf.woff b/static/api-docs/m_captcha/0.1.3/SourceSerifPro-Regular.ttf.woff new file mode 100644 index 0000000..a3d55cf Binary files /dev/null and b/static/api-docs/m_captcha/0.1.3/SourceSerifPro-Regular.ttf.woff differ diff --git a/static/api-docs/m_captcha/0.1.3/ayu.css b/static/api-docs/m_captcha/0.1.3/ayu.css new file mode 100644 index 0000000..096f6f3 --- /dev/null +++ b/static/api-docs/m_captcha/0.1.3/ayu.css @@ -0,0 +1 @@ + body{background-color:#0f1419;color:#c5c5c5;}h1,h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod){color:white;}h1.fqn{border-bottom-color:#5c6773;}h1.fqn a{color:#fff;}h2,h3:not(.impl):not(.method):not(.type):not(.tymethod){border-bottom-color:#5c6773;}h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant){border:none;}.in-band{background-color:#0f1419;}.invisible{background:rgba(0,0,0,0);}code{color:#ffb454;}h3>code,h4>code,h5>code{color:#e6e1cf;}pre>code{color:#e6e1cf;}span code{color:#e6e1cf;}.docblock a>code{color:#39AFD7 !important;}.docblock code,.docblock-short code{background-color:#191f26;}pre{color:#e6e1cf;background-color:#191f26;}.sidebar{background-color:#14191f;}.logo-container.rust-logo>img{filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);}*{scrollbar-color:#5c6773 transparent;}.sidebar{scrollbar-color:#5c6773 transparent;}::-webkit-scrollbar-track{background-color:transparent;}::-webkit-scrollbar-thumb{background-color:#5c6773;}.sidebar::-webkit-scrollbar-track{background-color:transparent;}.sidebar::-webkit-scrollbar-thumb{background-color:#5c6773;}.sidebar .current{background-color:transparent;color:#ffb44c;}.source .sidebar{background-color:#0f1419;}.sidebar .location{border-color:#000;background-color:#0f1419;color:#fff;}.sidebar-elems .location{color:#ff7733;}.sidebar-elems .location a{color:#fff;}.sidebar .version{border-bottom-color:#424c57;}.sidebar-title{border-top-color:#5c6773;border-bottom-color:#5c6773;}.block a:hover{background:transparent;color:#ffb44c;}.line-numbers span{color:#5c6773;}.line-numbers .line-highlighted{color:#708090;background-color:rgba(255,236,164,0.06);padding-right:4px;border-right:1px solid #ffb44c;}.docblock h1,.docblock h2,.docblock h3,.docblock h4,.docblock h5{border-bottom-color:#5c6773;}.docblock table,.docblock table td,.docblock table th{border-color:#5c6773;}.content .method .where,.content .fn .where,.content .where.fmt-newline{color:#c5c5c5;}.content .highlighted{color:#000 !important;background-color:#c6afb3;}.content .highlighted a,.content .highlighted span{color:#000 !important;}.content .highlighted{background-color:#c6afb3;}.search-results a{color:#0096cf;}.search-results a span.desc{color:#c5c5c5;}.content .item-info::before{color:#ccc;}.content span.foreigntype,.content a.foreigntype{color:#ef57ff;}.content span.union,.content a.union{color:#98a01c;}.content span.constant,.content a.constant,.content span.static,.content a.static{color:#6380a0;}.content span.primitive,.content a.primitive{color:#32889b;}.content span.traitalias,.content a.traitalias{color:#57d399;}.content span.keyword,.content a.keyword{color:#de5249;}.content span.externcrate,.content span.mod,.content a.mod{color:#acccf9;}.content span.struct,.content a.struct{color:#ffa0a5;}.content span.enum,.content a.enum{color:#99e0c9;}.content span.trait,.content a.trait{color:#39AFD7;}.content span.type,.content a.type{color:#cfbcf5;}.content span.fn,.content a.fn,.content span.method,.content a.method,.content span.tymethod,.content a.tymethod,.content .fnname{color:#fdd687;}.content span.attr,.content a.attr,.content span.derive,.content a.derive,.content span.macro,.content a.macro{color:#a37acc;}pre.rust .comment{color:#788797;}pre.rust .doccomment{color:#a1ac88;}nav:not(.sidebar){border-bottom-color:#424c57;}nav.main .current{border-top-color:#5c6773;border-bottom-color:#5c6773;}nav.main .separator{border:1px solid #5c6773;}a{color:#c5c5c5;}.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),.docblock-short a:not(.srclink):not(.test-arrow),.item-info a,#help a{color:#39AFD7;}.collapse-toggle{color:#999;}#crate-search{color:#c5c5c5;background-color:#141920;box-shadow:0 0 0 1px #424c57,0 0 0 2px transparent;border-color:#424c57;}.search-input{color:#ffffff;background-color:#141920;box-shadow:0 0 0 1px #424c57,0 0 0 2px transparent;transition:box-shadow 150ms ease-in-out;}#crate-search+.search-input:focus{box-shadow:0 0 0 1px #148099,0 0 0 2px transparent;}.search-focus:disabled{color:#929292;}.module-item .stab{color:#000;}.stab.unstable,.stab.deprecated,.stab.portability{color:#c5c5c5;background:#314559 !important;border-style:none !important;border-radius:4px;padding:3px 6px 3px 6px;}.stab.portability>code{color:#e6e1cf;background-color:transparent;}#help>div{background:#14191f;box-shadow:0px 6px 20px 0px black;border:none;border-radius:4px;}#help>div>span{border-bottom-color:#5c6773;}.since{color:grey;}tr.result span.primitive::after,tr.result span.keyword::after{color:#788797;}.line-numbers :target{background-color:transparent;}pre.rust .number,pre.rust .string{color:#b8cc52;}pre.rust .kw,pre.rust .kw-2,pre.rust .prelude-ty,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .op,pre.rust .lifetime{color:#ff7733;}pre.rust .macro,pre.rust .macro-nonterminal{color:#a37acc;}pre.rust .question-mark{color:#ff9011;}pre.rust .self{color:#36a3d9;font-style:italic;}pre.rust .attribute{color:#e6e1cf;}pre.rust .attribute .ident,pre.rust .attribute .op{color:#e6e1cf;}.example-wrap>pre.line-number{color:#5c67736e;border:none;}a.test-arrow{font-size:100%;color:#788797;border-radius:4px;background-color:rgba(57,175,215,0.09);}a.test-arrow:hover{background-color:rgba(57,175,215,0.368);color:#c5c5c5;}.toggle-label{color:#999;}:target>code,:target>.in-band{background:rgba(255,236,164,0.06);border-right:3px solid rgba(255,180,76,0.85);}pre.compile_fail{border-left:2px solid rgba(255,0,0,.4);}pre.compile_fail:hover,.information:hover+pre.compile_fail{border-left:2px solid #f00;}pre.should_panic{border-left:2px solid rgba(255,0,0,.4);}pre.should_panic:hover,.information:hover+pre.should_panic{border-left:2px solid #f00;}pre.ignore{border-left:2px solid rgba(255,142,0,.6);}pre.ignore:hover,.information:hover+pre.ignore{border-left:2px solid #ff9200;}.tooltip.compile_fail{color:rgba(255,0,0,.5);}.information>.compile_fail:hover{color:#f00;}.tooltip.should_panic{color:rgba(255,0,0,.5);}.information>.should_panic:hover{color:#f00;}.tooltip.ignore{color:rgba(255,142,0,.6);}.information>.ignore:hover{color:#ff9200;}.search-failed a{color:#39AFD7;}.tooltip::after{background-color:#314559;color:#c5c5c5;border:1px solid #5c6773;}.tooltip::before{border-color:transparent #314559 transparent transparent;}.notable-traits-tooltiptext{background-color:#314559;border-color:#5c6773;}#titles>button.selected{background-color:#141920 !important;border-bottom:1px solid #ffb44c !important;border-top:none;}#titles>button:not(.selected){background-color:transparent !important;border:none;}#titles>button:hover{border-bottom:1px solid rgba(242,151,24,0.3);}#titles>button>div.count{color:#888;}.content .highlighted.mod,.content .highlighted.externcrate{}.search-input:focus{}.content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,.block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro{}.content .highlighted.trait{}.content span.struct,.content a.struct,.block a.current.struct{}#titles>button:hover,#titles>button.selected{}.content .highlighted.traitalias{}.content span.type,.content a.type,.block a.current.type{}.content span.union,.content a.union,.block a.current.union{}.content .highlighted.foreigntype{}pre.rust .lifetime{}.content .highlighted.primitive{}.content .highlighted.constant,.content .highlighted.static{}.stab.unstable{}.content .highlighted.fn,.content .highlighted.method,.content .highlighted.tymethod{}h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod){}.content span.enum,.content a.enum,.block a.current.enum{}.content span.constant,.content a.constant,.block a.current.constant,.content span.static,.content a.static,.block a.current.static{}.content span.keyword,.content a.keyword,.block a.current.keyword{}pre.rust .comment{}.content .highlighted.enum{}.content .highlighted.struct{}.content .highlighted.keyword{}.content span.traitalias,.content a.traitalias,.block a.current.traitalias{}.content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method,.block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,.content .fnname{}pre.rust .kw{}pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute,pre.rust .attribute .ident{}.content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype{}pre.rust .doccomment{}.stab.deprecated{}.content .highlighted.attr,.content .highlighted.derive,.content .highlighted.macro{}.stab.portability{}.content .highlighted.union{}.content span.primitive,.content a.primitive,.block a.current.primitive{}.content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod{}.content .highlighted.type{}pre.rust .kw-2,pre.rust .prelude-ty{}.content span.trait,.content a.trait,.block a.current.trait{}@media (max-width:700px){.sidebar-menu{background-color:#14191f;border-bottom-color:#5c6773;border-right-color:#5c6773;}.sidebar-elems{background-color:#14191f;border-right-color:#5c6773;}#sidebar-filler{background-color:#14191f;border-bottom-color:#5c6773;}}kbd{color:#c5c5c5;background-color:#314559;border-color:#5c6773;border-bottom-color:#5c6773;box-shadow-color:#c6cbd1;}#theme-picker,#settings-menu,.help-button{border-color:#5c6773;background-color:#0f1419;color:#fff;}#theme-picker>img,#settings-menu>img{filter:invert(100);}#theme-picker:hover,#theme-picker:focus,#settings-menu:hover,#settings-menu:focus,.help-button:hover,.help-button:focus{border-color:#e0e0e0;}#theme-choices{border-color:#5c6773;background-color:#0f1419;}#theme-choices>button:not(:first-child){border-top-color:#5c6773;}#theme-choices>button:hover,#theme-choices>button:focus{background-color:rgba(110,110,110,0.33);}@media (max-width:700px){#theme-picker{background:#0f1419;}}#all-types{background-color:#14191f;}#all-types:hover{background-color:rgba(70,70,70,0.33);}.search-results td span.alias{color:#c5c5c5;}.search-results td span.grey{color:#999;}#sidebar-toggle{background-color:#14191f;}#sidebar-toggle:hover{background-color:rgba(70,70,70,0.33);}#source-sidebar{background-color:#14191f;}#source-sidebar>.title{color:#fff;border-bottom-color:#5c6773;}div.files>a:hover,div.name:hover{background-color:#14191f;color:#ffb44c;}div.files>.selected{background-color:#14191f;color:#ffb44c;}.setting-line>.title{border-bottom-color:#5c6773;}input:checked+.slider{background-color:#ffb454 !important;} \ No newline at end of file diff --git a/static/api-docs/m_captcha/0.1.3/brush.svg b/static/api-docs/m_captcha/0.1.3/brush.svg new file mode 100644 index 0000000..ea266e8 --- /dev/null +++ b/static/api-docs/m_captcha/0.1.3/brush.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/api-docs/m_captcha/0.1.3/cfg_if/all.html b/static/api-docs/m_captcha/0.1.3/cfg_if/all.html new file mode 100644 index 0000000..fb218fa --- /dev/null +++ b/static/api-docs/m_captcha/0.1.3/cfg_if/all.html @@ -0,0 +1,6 @@ +
A macro for defining #[cfg]
if-else statements.
The macro provided by this crate, cfg_if
, is similar to the if/elif
C
+preprocessor macro by allowing definition of a cascade of #[cfg]
cases,
+emitting the implementation which matches first.
This allows you to conveniently provide a long list #[cfg]
'd blocks of code
+without having to rewrite each clause multiple times.
+cfg_if::cfg_if! { + if #[cfg(unix)] { + fn foo() { /* unix specific functionality */ } + } else if #[cfg(target_pointer_width = "32")] { + fn foo() { /* non-unix, 32-bit functionality */ } + } else { + fn foo() { /* fallback implementation */ } + } +} +
cfg_if | The main macro provided by this crate. See crate documentation for more +information. + |
Redirecting to macro.cfg_if.html...
+ + + \ No newline at end of file diff --git a/static/api-docs/m_captcha/0.1.3/cfg_if/macro.cfg_if.html b/static/api-docs/m_captcha/0.1.3/cfg_if/macro.cfg_if.html new file mode 100644 index 0000000..cbde7d5 --- /dev/null +++ b/static/api-docs/m_captcha/0.1.3/cfg_if/macro.cfg_if.html @@ -0,0 +1,23 @@ +The main macro provided by this crate. See crate documentation for more +information.
+In-memory cache implementation that uses HashMap
+HashCache | cache datastructure implementing Save + |
cache datastructure implementing Save
+impl Actor for HashCache
[src]type Context = Context<Self>
Actor execution context type
+pub fn started(&mut self, ctx: &mut Self::Context)
pub fn stopping(&mut self, ctx: &mut Self::Context) -> Running
pub fn stopped(&mut self, ctx: &mut Self::Context)
pub fn start(self) -> Addr<Self> where
Self: Actor<Context = Context<Self>>,
pub fn start_default() -> Addr<Self> where
Self: Actor<Context = Context<Self>> + Default,
pub fn start_in_arbiter<F>(arb: &Arbiter, f: F) -> Addr<Self> where
Self: Actor<Context = Context<Self>>,
F: FnOnce(&mut Context<Self>) -> Self + Send + 'static,
pub fn create<F>(f: F) -> Addr<Self> where
Self: Actor<Context = Context<Self>>,
F: FnOnce(&mut Context<Self>) -> Self,
impl Clone for HashCache
[src]impl Default for HashCache
[src]impl Handler<CachePoW> for HashCache
[src]cache a PoWConfig
+type Result = MessageResult<CachePoW>
The type of value that this handler will return. Read more
+fn handle(&mut self, msg: CachePoW, ctx: &mut Self::Context) -> Self::Result
[src]impl Handler<CacheResult> for HashCache
[src]cache PoW result
+type Result = MessageResult<CacheResult>
The type of value that this handler will return. Read more
+fn handle(&mut self, msg: CacheResult, ctx: &mut Self::Context) -> Self::Result
[src]impl Handler<DeleteCaptchaResult> for HashCache
[src]Delte a PoWConfig
+type Result = MessageResult<DeleteCaptchaResult>
The type of value that this handler will return. Read more
+fn handle(
&mut self,
msg: DeleteCaptchaResult,
_ctx: &mut Self::Context
) -> Self::Result
[src]impl Handler<DeletePoW> for HashCache
[src]Delte a PoWConfig
+type Result = MessageResult<DeletePoW>
The type of value that this handler will return. Read more
+fn handle(&mut self, msg: DeletePoW, _ctx: &mut Self::Context) -> Self::Result
[src]impl Handler<RetrivePoW> for HashCache
[src]Retrive PoW difficulty_factor for a PoW string
+type Result = MessageResult<RetrivePoW>
The type of value that this handler will return. Read more
+fn handle(&mut self, msg: RetrivePoW, _ctx: &mut Self::Context) -> Self::Result
[src]impl Handler<VerifyCaptchaResult> for HashCache
[src]Retrive PoW difficulty_factor for a PoW string
+type Result = MessageResult<VerifyCaptchaResult>
The type of value that this handler will return. Read more
+fn handle(
&mut self,
msg: VerifyCaptchaResult,
_ctx: &mut Self::Context
) -> Self::Result
[src]impl Save for HashCache
[src]impl RefUnwindSafe for HashCache
[src]impl Send for HashCache
[src]impl Sync for HashCache
[src]impl Unpin for HashCache
[src]impl UnwindSafe for HashCache
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
message datatypes to interact with MCaptcha actor +Cache is used to save proofof work details and nonces to prevent replay attacks +and rainbow/dictionary attacks
+pub use hashcache::HashCache; |
hashcache | In-memory cache implementation that uses HashMap + |
messages | Messages that can be sent to cache data structures implementing Save + |
Save | Describes actor handler trait impls that are required by a cache implementation + |
Messages that can be sent to cache data structures implementing Save
+CachePoW | Message to cache PoW difficulty factor and string + |
CachePoWBuilder | Builder for |
CacheResult | Message to cache captcha result and the captcha key for which +it was generated + |
CacheResultBuilder | Builder for |
CachedPoWConfig | |
DeleteCaptchaResult | Message to delete cached capthca result when it expires + |
DeletePoW | Message to delete cached PoW difficulty factor and string +when they expire + |
RetrivePoW | Message to retrive the the difficulty factor for the specified +string from the cache + |
VerifyCaptchaResult | Message to verify captcha result against +the stored captcha key + |
Message to cache PoW difficulty factor and string
+string: String
difficulty_factor: u32
duration: u64
impl Cache
[src]pub fn new(p: &PoWConfig, v: &AddVisitorResult) -> Self
[src]impl<'de> Deserialize<'de> for Cache
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl Handler<Cache> for HashCache
[src]cache a PoWConfig
+type Result = MessageResult<Cache>
The type of value that this handler will return. Read more
+fn handle(&mut self, msg: Cache, ctx: &mut Self::Context) -> Self::Result
[src]impl Message for Cache
[src]type Result = CaptchaResult<()>
The type of value that this message will resolved with if it is +successful. Read more
+impl Serialize for Cache
[src]impl RefUnwindSafe for Cache
[src]impl Send for Cache
[src]impl Sync for Cache
[src]impl Unpin for Cache
[src]impl UnwindSafe for Cache
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Builder for Cache
.
impl CacheBuilder
[src]pub fn string(&mut self, value: String) -> &mut Self
[src]pub fn difficulty_factor(&mut self, value: u32) -> &mut Self
[src]pub fn duration(&mut self, value: u64) -> &mut Self
[src]pub fn build(&self) -> Result<Cache, String>
[src]impl Clone for CacheBuilder
[src]fn clone(&self) -> CacheBuilder
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl Default for CacheBuilder
[src]fn default() -> CacheBuilder
[src]impl RefUnwindSafe for CacheBuilder
[src]impl Send for CacheBuilder
[src]impl Sync for CacheBuilder
[src]impl Unpin for CacheBuilder
[src]impl UnwindSafe for CacheBuilder
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to cache PoW difficulty factor and string
+string: String
difficulty_factor: u32
duration: u64
key: String
impl Clone for CachePoW
[src]impl<'de> Deserialize<'de> for CachePoW
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl Handler<CachePoW> for HashCache
[src]cache a PoWConfig
+type Result = MessageResult<CachePoW>
The type of value that this handler will return. Read more
+fn handle(&mut self, msg: CachePoW, ctx: &mut Self::Context) -> Self::Result
[src]impl Message for CachePoW
[src]type Result = CaptchaResult<()>
The type of value that this message will resolved with if it is +successful. Read more
+impl Serialize for CachePoW
[src]impl RefUnwindSafe for CachePoW
[src]impl Send for CachePoW
[src]impl Sync for CachePoW
[src]impl Unpin for CachePoW
[src]impl UnwindSafe for CachePoW
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Builder for CachePoW
.
impl CachePoWBuilder
[src]pub fn string(&mut self, value: String) -> &mut Self
[src]pub fn difficulty_factor(&mut self, value: u32) -> &mut Self
[src]pub fn duration(&mut self, value: u64) -> &mut Self
[src]pub fn key(&mut self, value: String) -> &mut Self
[src]pub fn build(&self) -> Result<CachePoW, String>
[src]impl Clone for CachePoWBuilder
[src]fn clone(&self) -> CachePoWBuilder
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl Default for CachePoWBuilder
[src]fn default() -> CachePoWBuilder
[src]impl RefUnwindSafe for CachePoWBuilder
[src]impl Send for CachePoWBuilder
[src]impl Sync for CachePoWBuilder
[src]impl Unpin for CachePoWBuilder
[src]impl UnwindSafe for CachePoWBuilder
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to cache captcha result and the captcha key for which +it was generated
+token: String
key: String
duration: u64
impl<'de> Deserialize<'de> for CacheResult
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl From<CachedPoWConfig> for CacheResult
[src]fn from(c: CachedPoWConfig) -> Self
[src]impl Handler<CacheResult> for HashCache
[src]cache PoW result
+type Result = MessageResult<CacheResult>
The type of value that this handler will return. Read more
+fn handle(&mut self, msg: CacheResult, ctx: &mut Self::Context) -> Self::Result
[src]impl Message for CacheResult
[src]type Result = CaptchaResult<()>
The type of value that this message will resolved with if it is +successful. Read more
+impl Serialize for CacheResult
[src]impl RefUnwindSafe for CacheResult
[src]impl Send for CacheResult
[src]impl Sync for CacheResult
[src]impl Unpin for CacheResult
[src]impl UnwindSafe for CacheResult
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Builder for CacheResult
.
impl CacheResultBuilder
[src]pub fn token(&mut self, value: String) -> &mut Self
[src]pub fn key(&mut self, value: String) -> &mut Self
[src]pub fn duration(&mut self, value: u64) -> &mut Self
[src]pub fn build(&self) -> Result<CacheResult, String>
[src]impl Clone for CacheResultBuilder
[src]fn clone(&self) -> CacheResultBuilder
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl Default for CacheResultBuilder
[src]fn default() -> CacheResultBuilder
[src]impl RefUnwindSafe for CacheResultBuilder
[src]impl Send for CacheResultBuilder
[src]impl Sync for CacheResultBuilder
[src]impl Unpin for CacheResultBuilder
[src]impl UnwindSafe for CacheResultBuilder
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
key: String
difficulty_factor: u32
duration: u64
impl Clone for CachedPoWConfig
[src]fn clone(&self) -> CachedPoWConfig
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl Debug for CachedPoWConfig
[src]impl Default for CachedPoWConfig
[src]fn default() -> CachedPoWConfig
[src]impl<'de> Deserialize<'de> for CachedPoWConfig
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl From<CachedPoWConfig> for CacheResult
[src]fn from(c: CachedPoWConfig) -> Self
[src]impl PartialEq<CachedPoWConfig> for CachedPoWConfig
[src]fn eq(&self, other: &CachedPoWConfig) -> bool
[src]fn ne(&self, other: &CachedPoWConfig) -> bool
[src]impl Serialize for CachedPoWConfig
[src]fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error> where
__S: Serializer,
[src]impl StructuralPartialEq for CachedPoWConfig
[src]impl RefUnwindSafe for CachedPoWConfig
[src]impl Send for CachedPoWConfig
[src]impl Sync for CachedPoWConfig
[src]impl Unpin for CachedPoWConfig
[src]impl UnwindSafe for CachedPoWConfig
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to delete cached capthca result when it expires
+token: String
impl Handler<DeleteCaptchaResult> for HashCache
[src]Delte a PoWConfig
+type Result = MessageResult<DeleteCaptchaResult>
The type of value that this handler will return. Read more
+fn handle(
&mut self,
msg: DeleteCaptchaResult,
_ctx: &mut Self::Context
) -> Self::Result
[src]impl Message for DeleteCaptchaResult
[src]type Result = CaptchaResult<()>
The type of value that this message will resolved with if it is +successful. Read more
+impl RefUnwindSafe for DeleteCaptchaResult
[src]impl Send for DeleteCaptchaResult
[src]impl Sync for DeleteCaptchaResult
[src]impl Unpin for DeleteCaptchaResult
[src]impl UnwindSafe for DeleteCaptchaResult
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to delete cached PoW difficulty factor and string +when they expire
+impl Handler<DeletePoW> for HashCache
[src]Delte a PoWConfig
+type Result = MessageResult<DeletePoW>
The type of value that this handler will return. Read more
+fn handle(&mut self, msg: DeletePoW, _ctx: &mut Self::Context) -> Self::Result
[src]impl Message for DeletePoW
[src]type Result = CaptchaResult<()>
The type of value that this message will resolved with if it is +successful. Read more
+impl RefUnwindSafe for DeletePoW
[src]impl Send for DeletePoW
[src]impl Sync for DeletePoW
[src]impl Unpin for DeletePoW
[src]impl UnwindSafe for DeletePoW
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to delete cached PoW difficulty factor and string +when they expire
+impl Handler<DeleteString> for HashCache
[src]Delte a PoWConfig
+type Result = MessageResult<DeleteString>
The type of value that this handler will return. Read more
+fn handle(
&mut self,
msg: DeleteString,
_ctx: &mut Self::Context
) -> Self::Result
[src]impl Message for DeleteString
[src]type Result = CaptchaResult<()>
The type of value that this message will resolved with if it is +successful. Read more
+impl RefUnwindSafe for DeleteString
[src]impl Send for DeleteString
[src]impl Sync for DeleteString
[src]impl Unpin for DeleteString
[src]impl UnwindSafe for DeleteString
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to retrive the the difficulty factor for the specified +string from the cache
+impl Handler<Retrive> for HashCache
[src]Retrive PoW difficulty_factor for a PoW string
+type Result = MessageResult<Retrive>
The type of value that this handler will return. Read more
+fn handle(&mut self, msg: Retrive, _ctx: &mut Self::Context) -> Self::Result
[src]impl Message for Retrive
[src]type Result = CaptchaResult<Option<u32>>
The type of value that this message will resolved with if it is +successful. Read more
+impl RefUnwindSafe for Retrive
[src]impl Send for Retrive
[src]impl Sync for Retrive
[src]impl Unpin for Retrive
[src]impl UnwindSafe for Retrive
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to retrive the the difficulty factor for the specified +string from the cache
+impl Handler<RetrivePoW> for HashCache
[src]Retrive PoW difficulty_factor for a PoW string
+type Result = MessageResult<RetrivePoW>
The type of value that this handler will return. Read more
+fn handle(&mut self, msg: RetrivePoW, _ctx: &mut Self::Context) -> Self::Result
[src]impl Message for RetrivePoW
[src]type Result = CaptchaResult<Option<CachedPoWConfig>>
The type of value that this message will resolved with if it is +successful. Read more
+impl RefUnwindSafe for RetrivePoW
[src]impl Send for RetrivePoW
[src]impl Sync for RetrivePoW
[src]impl Unpin for RetrivePoW
[src]impl UnwindSafe for RetrivePoW
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to verify captcha result against +the stored captcha key
+token: String
key: String
impl Clone for VerifyCaptchaResult
[src]fn clone(&self) -> VerifyCaptchaResult
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl<'de> Deserialize<'de> for VerifyCaptchaResult
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl Handler<VerifyCaptchaResult> for HashCache
[src]Retrive PoW difficulty_factor for a PoW string
+type Result = MessageResult<VerifyCaptchaResult>
The type of value that this handler will return. Read more
+fn handle(
&mut self,
msg: VerifyCaptchaResult,
_ctx: &mut Self::Context
) -> Self::Result
[src]impl Message for VerifyCaptchaResult
[src]type Result = CaptchaResult<bool>
The type of value that this message will resolved with if it is +successful. Read more
+impl Serialize for VerifyCaptchaResult
[src]impl RefUnwindSafe for VerifyCaptchaResult
[src]impl Send for VerifyCaptchaResult
[src]impl Sync for VerifyCaptchaResult
[src]impl Unpin for VerifyCaptchaResult
[src]impl UnwindSafe for VerifyCaptchaResult
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Describes actor handler trait impls that are required by a cache implementation
+Defense datatypes
+ ++use m_captcha::{LevelBuilder, DefenseBuilder}; +DefenseBuilder::default() + .add_level( + LevelBuilder::default() + .visitor_threshold(50) + .difficulty_factor(50) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .add_level( + LevelBuilder::default() + .visitor_threshold(500) + .difficulty_factor(500) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .build() + .unwrap();
Defense | struct describes all the different Levels at which an mCaptcha system operates + |
DefenseBuilder | Builder struct for Defense + |
Level | Level struct that describes threshold-difficulty factor mapping + |
LevelBuilder | Bulder struct for Level to describe threshold-difficulty factor mapping + |
struct describes all the different Levels at which an mCaptcha system operates
+impl Defense
[src]pub fn get_difficulty(&self) -> u32
[src]! Difficulty is calculated as:
+! rust ! let difficulty = u128::max_value() - u128::max_value() / difficulty_factor; !
+! The higher the difficulty_factor
, the higher the difficulty.
+Get difficulty factor of current level of defense
pub fn tighten_up(&mut self)
[src]tighten up defense. Increases defense level by a factor of one. +When defense is at max level, calling this method will have no effect
+pub fn loosen_up(&mut self)
[src]Loosen up defense. Decreases defense level by a factor of one. +When defense is at the lowest level, calling this method will have no effect.
+pub fn max_defense(&mut self)
[src]Set defense to maximum level
+pub fn min_defense(&mut self)
[src]Set defense to minimum level
+pub fn visitor_threshold(&self) -> u32
[src]Get current level's visitor threshold
+impl Clone for Defense
[src]impl Debug for Defense
[src]impl<'de> Deserialize<'de> for Defense
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl PartialEq<Defense> for Defense
[src]impl Serialize for Defense
[src]fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error> where
__S: Serializer,
[src]impl StructuralPartialEq for Defense
[src]impl RefUnwindSafe for Defense
[src]impl Send for Defense
[src]impl Sync for Defense
[src]impl Unpin for Defense
[src]impl UnwindSafe for Defense
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Builder struct for Defense
+impl DefenseBuilder
[src]pub fn add_level(&mut self, level: Level) -> CaptchaResult<&mut Self>
[src]add a level to Defense
+pub fn build(&mut self) -> CaptchaResult<Defense>
[src]Build Defense
+impl Clone for DefenseBuilder
[src]fn clone(&self) -> DefenseBuilder
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl Debug for DefenseBuilder
[src]impl Default for DefenseBuilder
[src]impl PartialEq<DefenseBuilder> for DefenseBuilder
[src]fn eq(&self, other: &DefenseBuilder) -> bool
[src]fn ne(&self, other: &DefenseBuilder) -> bool
[src]impl StructuralPartialEq for DefenseBuilder
[src]impl RefUnwindSafe for DefenseBuilder
[src]impl Send for DefenseBuilder
[src]impl Sync for DefenseBuilder
[src]impl Unpin for DefenseBuilder
[src]impl UnwindSafe for DefenseBuilder
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Level struct that describes threshold-difficulty factor mapping
+visitor_threshold: u32
difficulty_factor: u32
impl Clone for Level
[src]impl Copy for Level
[src]impl Debug for Level
[src]impl<'de> Deserialize<'de> for Level
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl PartialEq<Level> for Level
[src]impl Serialize for Level
[src]fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error> where
__S: Serializer,
[src]impl StructuralPartialEq for Level
[src]impl RefUnwindSafe for Level
[src]impl Send for Level
[src]impl Sync for Level
[src]impl Unpin for Level
[src]impl UnwindSafe for Level
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Bulder struct for Level to describe threshold-difficulty factor mapping
+impl LevelBuilder
[src]pub fn visitor_threshold(&mut self, visitor_threshold: u32) -> &mut Self
[src]set visitor count for level
+pub fn difficulty_factor(
&mut self,
difficulty_factor: u32
) -> CaptchaResult<&mut Self>
[src]set difficulty factor for level. difficulty_factor can't be zero because +Difficulty is calculated as:
+ ++let difficulty_factor = 500; +let difficulty = u128::max_value() - u128::max_value() / difficulty_factor;
the higher the difficulty_factor
, the higher the difficulty.
pub fn build(&mut self) -> CaptchaResult<Level>
[src]build Level struct
+impl Clone for LevelBuilder
[src]fn clone(&self) -> LevelBuilder
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl Copy for LevelBuilder
[src]impl Debug for LevelBuilder
[src]impl Default for LevelBuilder
[src]impl PartialEq<LevelBuilder> for LevelBuilder
[src]fn eq(&self, other: &LevelBuilder) -> bool
[src]fn ne(&self, other: &LevelBuilder) -> bool
[src]impl StructuralPartialEq for LevelBuilder
[src]impl RefUnwindSafe for LevelBuilder
[src]impl Send for LevelBuilder
[src]impl Sync for LevelBuilder
[src]impl Unpin for LevelBuilder
[src]impl UnwindSafe for LevelBuilder
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Error datatype
+When configuring m_captcha, DefenseBuilder
+must be passed atleast one LevelConfig
if not this error will arise
Visitor count must be a whole number(zero and above). +When configuring m_captcha, LevelBuilder. +difficulty_factor must be set to greater than zero.
+captcha cooldown duration must be greater than 0
+Difficulty factor must be set
+Visitor threshold must be set
+Visitor count must be Unique
+Difficulty factor should increase with level
+Difficulty factor should increase with level
+Happens when submitted work doesn't satisfy the required +difficulty factor
+Happens when submitted work is computed over string that +isn't in cache
+Happens when submitted work is computed over configuration intended for +a different mCAptcha sitekey
+Submitted PoW is invalid
+PleaseSetValue(String)
Used in builder structs when a value is not set
+impl Clone for CaptchaError
[src]fn clone(&self) -> CaptchaError
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl Debug for CaptchaError
[src]impl Display for CaptchaError
[src]impl Error for CaptchaError
[src]pub fn source(&self) -> Option<&(dyn Error + 'static)>
1.30.0[src]pub fn backtrace(&self) -> Option<&Backtrace>
[src]pub fn description(&self) -> &str
1.0.0[src]pub fn cause(&self) -> Option<&dyn Error>
1.0.0[src]impl PartialEq<CaptchaError> for CaptchaError
[src]fn eq(&self, other: &CaptchaError) -> bool
[src]fn ne(&self, other: &CaptchaError) -> bool
[src]impl StructuralPartialEq for CaptchaError
[src]impl RefUnwindSafe for CaptchaError
[src]impl Send for CaptchaError
[src]impl Sync for CaptchaError
[src]impl Unpin for CaptchaError
[src]impl UnwindSafe for CaptchaError
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T> ToString for T where
T: Display + ?Sized,
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Errors and Result module
+CaptchaError | Error datatype + |
CaptchaResult | Result datatype for m_captcha + |
type CaptchaResult<V> = Result<V, CaptchaError>;
Result datatype for m_captcha
+mCaptcha is a proof of work based Denaial-of-Service attack protection system. +This is is a server library that you can embed in your services to protect your +servers.
+A commercial managed solution is in the works but I'd much rather prefer +folks host their own instances as it will make the more decentralized and free.
+In mCaptcha, defense is adjusted in discrete levels that depend on the +ammount of traffic that a service is experiencing. So users of this library are +requested to benchmark their target machines before configuring their mCaptcha +component.
++use m_captcha::{ + cache::{messages::VerifyCaptchaResult, HashCache}, + master::{AddSiteBuilder, Master}, + pow::{ConfigBuilder, Work}, + system::SystemBuilder, + DefenseBuilder, LevelBuilder, MCaptchaBuilder, +}; +// traits from actix needs to be in scope for starting actor +use actix::prelude::*; + +#[actix_rt::main] +async fn main() -> std::io::Result<()> { + // start cahce actor + // cache is used to store PoW requirements that are sent to clients + // This way, it can be verified that the client computed work over a config + // that _we_ sent. Offers protection against rainbow tables powered dictionary attacks + let cache = HashCache::default().start(); + + // create PoW config with unique salt. Salt has to be safely guarded. + // salts protect us from replay attacks + let pow = ConfigBuilder::default() + .salt("myrandomsaltisnotlongenoug".into()) + .build() + .unwrap(); + + // start master actor. Master actor is responsible for managing MCaptcha actors + // each mCaptcha system should have only one master + let master = Master::new(5).start(); + + // Create system. System encapsulates master and cache and provides useful abstraction + // each mCaptcha system should have only one system + let system = SystemBuilder::default() + .master(master) + .cache(cache) + .pow(pow.clone()) + .build() + .unwrap(); + + // configure defense. This is a per site configuration. A site can have several levels + // of defenses configured + let defense = DefenseBuilder::default() + // add as many defense as you see fit + .add_level( + LevelBuilder::default() + // visitor_threshold is the threshold/limit at which + // mCaptcha will adjust difficulty defense + // it is advisable to set small values for the first + // defense visitor_threshold and difficulty_factor + // as this will be the work that clients will be + // computing when there's no load + .visitor_threshold(50) + .difficulty_factor(500) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .add_level( + LevelBuilder::default() + .visitor_threshold(5000) + .difficulty_factor(50000) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .build() + .unwrap(); + + // create and start MCaptcha actor that uses the above defense configuration + // This is what manages the difficulty factor of sites that an mCaptcha protects + let mcaptcha = MCaptchaBuilder::default() + .defense(defense) + // leaky bucket algorithm's emission interval + .duration(30) + // .cache(cache) + .build() + .unwrap() + .start(); + + // unique value identifying an MCaptcha actor + let mcaptcha_name = "batsense.net"; + + // add MCaptcha to Master + let msg = AddSiteBuilder::default() + .id(mcaptcha_name.into()) + .addr(mcaptcha.clone()) + .build() + .unwrap(); + system.master.send(msg).await.unwrap(); + + // Get PoW config. Should be called everytime there's a visitor for a + // managed site(here mcaptcha_name) + let work_req = system.get_pow(mcaptcha_name.into()).await.unwrap(); + + // the following computation should be done on the client but for the purpose + // of this illustration, we are going to do it on the server it self + let work = pow + .prove_work(&work_req.string, work_req.difficulty_factor) + .unwrap(); + + // the payload that the client sends to the server + let payload = Work { + string: work_req.string, + result: work.result, + nonce: work.nonce, + key: mcaptcha_name.into(), + }; + + // Server evaluates client's work. Returns true if everything + // checksout and Err() if something fishy is happening + let res = system.verify_pow(payload.clone()).await; + assert!(res.is_ok()); + + // The client should submit the token to the mCaptcha protected service + // The service should validate the token received from the client + // with the mCaptcha server before processing client's + // request + + // mcaptcha protected service sends the following paylaod to mCaptcha + // server: + let verify_msg = VerifyCaptchaResult { + token: res.unwrap(), + key: mcaptcha_name.into(), + }; + + // on mCaptcha server: + let res = system.validate_verification_tokens(verify_msg).await; + // mCaptcha will return true if token is valid and false if + // token is invalid + assert!(res.is_ok()); + assert!(res.unwrap()); + + Ok(()) +}
pub use crate::cache::hashcache::HashCache; |
pub use defense::Defense; |
pub use defense::DefenseBuilder; |
pub use defense::LevelBuilder; |
pub use mcaptcha::MCaptcha; |
pub use mcaptcha::MCaptchaBuilder; |
cache | message datatypes to interact with MCaptcha actor +Cache is used to save proofof work details and nonces to prevent replay attacks +and rainbow/dictionary attacks + |
defense | Defense datatypes + |
errors | Errors and Result module + |
master | + |
mcaptcha | MCaptcha actor module that manages defense levels + |
pow | PoW datatypes used in client-server interaction + |
system | module describing mCaptcha system + |
AddSite | + |
AddSiteBuilder | Builder for |
CleanUp | Message to clean up master of MCaptcha actors with zero visitor count + |
GetSite | Message to get an MCaptcha actor from master + |
Master | This Actor manages the MCaptcha actors. +A service can have several MCaptcha actors with +varying Defense configurations +so a "master" actor is needed to manage them all + |
RemoveSite | Message to delete MCaptcha actor + |
id: String
addr: Addr<MCaptcha>
impl Handler<AddSite> for Master
[src]type Result = ()
The type of value that this handler will return. Read more
+fn handle(&mut self, m: AddSite, _ctx: &mut Self::Context) -> Self::Result
[src]impl Message for AddSite
[src]impl !RefUnwindSafe for AddSite
[src]impl Send for AddSite
[src]impl Sync for AddSite
[src]impl Unpin for AddSite
[src]impl !UnwindSafe for AddSite
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Builder for AddSite
.
impl AddSiteBuilder
[src]pub fn id(&mut self, value: String) -> &mut Self
[src]pub fn addr(&mut self, value: Addr<MCaptcha>) -> &mut Self
[src]pub fn build(&self) -> Result<AddSite, String>
[src]impl Clone for AddSiteBuilder
[src]fn clone(&self) -> AddSiteBuilder
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl Default for AddSiteBuilder
[src]fn default() -> AddSiteBuilder
[src]impl !RefUnwindSafe for AddSiteBuilder
[src]impl Send for AddSiteBuilder
[src]impl Sync for AddSiteBuilder
[src]impl Unpin for AddSiteBuilder
[src]impl !UnwindSafe for AddSiteBuilder
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to clean up master of MCaptcha actors with zero visitor count
+impl Handler<CleanUp> for Master
[src]type Result = ()
The type of value that this handler will return. Read more
+fn handle(&mut self, _: CleanUp, ctx: &mut Self::Context) -> Self::Result
[src]impl Message for CleanUp
[src]impl RefUnwindSafe for CleanUp
[src]impl Send for CleanUp
[src]impl Sync for CleanUp
[src]impl Unpin for CleanUp
[src]impl UnwindSafe for CleanUp
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to get an MCaptcha actor from master
+impl Handler<GetSite> for Master
[src]type Result = MessageResult<GetSite>
The type of value that this handler will return. Read more
+fn handle(&mut self, m: GetSite, _ctx: &mut Self::Context) -> Self::Result
[src]impl Message for GetSite
[src]impl RefUnwindSafe for GetSite
[src]impl Send for GetSite
[src]impl Sync for GetSite
[src]impl Unpin for GetSite
[src]impl UnwindSafe for GetSite
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
This Actor manages the MCaptcha actors. +A service can have several MCaptcha actors with +varying Defense configurations +so a "master" actor is needed to manage them all
+impl Master
[src]pub fn add_site(&mut self, details: AddSite)
[src]pub fn new(gc: u64) -> Self
[src]create new master
+accepts a u64
to configure garbage collection period
pub fn get_site<'a, 'b>(&'a mut self, id: &'b str) -> Option<Addr<MCaptcha>>
[src]pub fn rm_site(&mut self, id: &str)
[src]impl Actor for Master
[src]type Context = Context<Self>
Actor execution context type
+fn started(&mut self, ctx: &mut Self::Context)
[src]pub fn stopping(&mut self, ctx: &mut Self::Context) -> Running
pub fn stopped(&mut self, ctx: &mut Self::Context)
pub fn start(self) -> Addr<Self> where
Self: Actor<Context = Context<Self>>,
pub fn start_default() -> Addr<Self> where
Self: Actor<Context = Context<Self>> + Default,
pub fn start_in_arbiter<F>(arb: &Arbiter, f: F) -> Addr<Self> where
Self: Actor<Context = Context<Self>>,
F: FnOnce(&mut Context<Self>) -> Self + Send + 'static,
pub fn create<F>(f: F) -> Addr<Self> where
Self: Actor<Context = Context<Self>>,
F: FnOnce(&mut Context<Self>) -> Self,
impl Clone for Master
[src]impl Handler<AddSite> for Master
[src]type Result = ()
The type of value that this handler will return. Read more
+fn handle(&mut self, m: AddSite, _ctx: &mut Self::Context) -> Self::Result
[src]impl Handler<CleanUp> for Master
[src]type Result = ()
The type of value that this handler will return. Read more
+fn handle(&mut self, _: CleanUp, ctx: &mut Self::Context) -> Self::Result
[src]impl Handler<GetSite> for Master
[src]type Result = MessageResult<GetSite>
The type of value that this handler will return. Read more
+fn handle(&mut self, m: GetSite, _ctx: &mut Self::Context) -> Self::Result
[src]impl Handler<RemoveSite> for Master
[src]impl !RefUnwindSafe for Master
[src]impl Send for Master
[src]impl Sync for Master
[src]impl Unpin for Master
[src]impl !UnwindSafe for Master
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to delete MCaptcha actor
+impl Handler<RemoveSite> for Master
[src]type Result = ()
The type of value that this handler will return. Read more
+fn handle(&mut self, m: RemoveSite, _ctx: &mut Self::Context) -> Self::Result
[src]impl Message for RemoveSite
[src]impl RefUnwindSafe for RemoveSite
[src]impl Send for RemoveSite
[src]impl Sync for RemoveSite
[src]impl Unpin for RemoveSite
[src]impl UnwindSafe for RemoveSite
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
MCaptcha actor module that manages defense levels
++use m_captcha::{mcaptcha::AddVisitor, MCaptchaBuilder, cache::HashCache, LevelBuilder, DefenseBuilder}; +// traits from actix needs to be in scope for starting actor +use actix::prelude::*; + +#[actix_rt::main] +async fn main() -> std::io::Result<()> { + // configure defense + let defense = DefenseBuilder::default() + // add as many levels as you see fit + .add_level( + LevelBuilder::default() + // visitor_threshold is the threshold/limit at which + // mCaptcha will adjust difficulty levels + // it is advisable to set small values for the first + // levels visitor_threshold and difficulty_factor + // as this will be the work that clients will be + // computing when there's no load + .visitor_threshold(50) + .difficulty_factor(500) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .add_level( + LevelBuilder::default() + .visitor_threshold(5000) + .difficulty_factor(50000) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .build() + .unwrap(); + + // create and start MCaptcha actor + //let cache = HashCache::default().start(); + let mcaptcha = MCaptchaBuilder::default() + .defense(defense) + // leaky bucket algorithm's emission interval + .duration(30) + .build() + .unwrap() + .start(); + + // increment count when user visits protected routes + mcaptcha.send(AddVisitor).await.unwrap(); + + Ok(()) +}
AddVisitor | Message to increment the visitor count +returns difficulty factor and lifetime + |
AddVisitorResult | Struct representing the return datatime of +AddVisitor message. Contains MCaptcha lifetime +and difficulty factor + |
GetCurrentVisitorCount | Message to get the visitor count + |
MCaptcha | This struct represents the mCaptcha state and is used +to configure leaky-bucket lifetime and manage defense + |
MCaptchaBuilder | Builder for MCaptcha + |
Stop | Message to stop MCaptcha + |
Message to increment the visitor count +returns difficulty factor and lifetime
+impl Handler<AddVisitor> for MCaptcha
[src]type Result = MessageResult<AddVisitor>
The type of value that this handler will return. Read more
+fn handle(&mut self, _: AddVisitor, ctx: &mut Self::Context) -> Self::Result
[src]impl Message for AddVisitor
[src]type Result = AddVisitorResult
The type of value that this message will resolved with if it is +successful. Read more
+impl RefUnwindSafe for AddVisitor
[src]impl Send for AddVisitor
[src]impl Sync for AddVisitor
[src]impl Unpin for AddVisitor
[src]impl UnwindSafe for AddVisitor
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Struct representing the return datatime of +AddVisitor message. Contains MCaptcha lifetime +and difficulty factor
+duration: u64
difficulty_factor: u32
impl Clone for AddVisitorResult
[src]fn clone(&self) -> AddVisitorResult
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl Debug for AddVisitorResult
[src]impl<'de> Deserialize<'de> for AddVisitorResult
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl Serialize for AddVisitorResult
[src]impl RefUnwindSafe for AddVisitorResult
[src]impl Send for AddVisitorResult
[src]impl Sync for AddVisitorResult
[src]impl Unpin for AddVisitorResult
[src]impl UnwindSafe for AddVisitorResult
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to get the visitor count
+impl Handler<GetCurrentVisitorCount> for MCaptcha
[src]type Result = MessageResult<GetCurrentVisitorCount>
The type of value that this handler will return. Read more
+fn handle(
&mut self,
_: GetCurrentVisitorCount,
_ctx: &mut Self::Context
) -> Self::Result
[src]impl Message for GetCurrentVisitorCount
[src]impl RefUnwindSafe for GetCurrentVisitorCount
[src]impl Send for GetCurrentVisitorCount
[src]impl Sync for GetCurrentVisitorCount
[src]impl Unpin for GetCurrentVisitorCount
[src]impl UnwindSafe for GetCurrentVisitorCount
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
This struct represents the mCaptcha state and is used +to configure leaky-bucket lifetime and manage defense
+impl MCaptcha
[src]pub fn add_visitor(&mut self)
[src]increments the visitor count by one
+pub fn decrement_visitor(&mut self)
[src]decrements the visitor count by one
+pub fn get_difficulty(&self) -> u32
[src]get current difficulty factor
+pub fn get_duration(&self) -> u64
[src]get MCaptcha's lifetime
+impl Actor for MCaptcha
[src]type Context = Context<Self>
Actor execution context type
+pub fn started(&mut self, ctx: &mut Self::Context)
pub fn stopping(&mut self, ctx: &mut Self::Context) -> Running
pub fn stopped(&mut self, ctx: &mut Self::Context)
pub fn start(self) -> Addr<Self> where
Self: Actor<Context = Context<Self>>,
pub fn start_default() -> Addr<Self> where
Self: Actor<Context = Context<Self>> + Default,
pub fn start_in_arbiter<F>(arb: &Arbiter, f: F) -> Addr<Self> where
Self: Actor<Context = Context<Self>>,
F: FnOnce(&mut Context<Self>) -> Self + Send + 'static,
pub fn create<F>(f: F) -> Addr<Self> where
Self: Actor<Context = Context<Self>>,
F: FnOnce(&mut Context<Self>) -> Self,
impl Clone for MCaptcha
[src]impl Debug for MCaptcha
[src]impl<'de> Deserialize<'de> for MCaptcha
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl Handler<AddVisitor> for MCaptcha
[src]type Result = MessageResult<AddVisitor>
The type of value that this handler will return. Read more
+fn handle(&mut self, _: AddVisitor, ctx: &mut Self::Context) -> Self::Result
[src]impl Handler<GetCurrentVisitorCount> for MCaptcha
[src]type Result = MessageResult<GetCurrentVisitorCount>
The type of value that this handler will return. Read more
+fn handle(
&mut self,
_: GetCurrentVisitorCount,
_ctx: &mut Self::Context
) -> Self::Result
[src]impl Handler<Stop> for MCaptcha
[src]type Result = ()
The type of value that this handler will return. Read more
+fn handle(&mut self, _: Stop, ctx: &mut Self::Context) -> Self::Result
[src]impl Serialize for MCaptcha
[src]impl RefUnwindSafe for MCaptcha
[src]impl Send for MCaptcha
[src]impl Sync for MCaptcha
[src]impl Unpin for MCaptcha
[src]impl UnwindSafe for MCaptcha
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Builder for MCaptcha
+impl MCaptchaBuilder
[src]pub fn defense(&mut self, d: Defense) -> &mut Self
[src]set defense
+pub fn duration(&mut self, d: u64) -> &mut Self
[src]set duration
+pub fn build(&mut self) -> CaptchaResult<MCaptcha>
[src]Builds new MCaptcha
+impl Clone for MCaptchaBuilder
[src]fn clone(&self) -> MCaptchaBuilder
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl Debug for MCaptchaBuilder
[src]impl Default for MCaptchaBuilder
[src]impl<'de> Deserialize<'de> for MCaptchaBuilder
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl Serialize for MCaptchaBuilder
[src]impl RefUnwindSafe for MCaptchaBuilder
[src]impl Send for MCaptchaBuilder
[src]impl Sync for MCaptchaBuilder
[src]impl Unpin for MCaptchaBuilder
[src]impl UnwindSafe for MCaptchaBuilder
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to stop MCaptcha
+impl Handler<Stop> for MCaptcha
[src]type Result = ()
The type of value that this handler will return. Read more
+fn handle(&mut self, _: Stop, ctx: &mut Self::Context) -> Self::Result
[src]impl Message for Stop
[src]impl RefUnwindSafe for Stop
[src]impl Send for Stop
[src]impl Sync for Stop
[src]impl Unpin for Stop
[src]impl UnwindSafe for Stop
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Message to increment the visitor count +returns difficulty factor and lifetime
+impl Handler<Visitor> for MCaptcha
[src]type Result = MessageResult<Visitor>
The type of value that this handler will return. Read more
+fn handle(&mut self, _: Visitor, ctx: &mut Self::Context) -> Self::Result
[src]impl Message for Visitor
[src]type Result = VisitorResult
The type of value that this message will resolved with if it is +successful. Read more
+impl RefUnwindSafe for Visitor
[src]impl Send for Visitor
[src]impl Sync for Visitor
[src]impl Unpin for Visitor
[src]impl UnwindSafe for Visitor
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Struct representing the return datatime of +Visitor message. Contains MCaptcha lifetime +and difficulty factor
+duration: u64
difficulty_factor: u32
impl RefUnwindSafe for VisitorResult
[src]impl Send for VisitorResult
[src]impl Sync for VisitorResult
[src]impl Unpin for VisitorResult
[src]impl UnwindSafe for VisitorResult
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
PoW datatypes used in client-server interaction
+ConfigBuilder | Builder for |
PoWConfig | PoW requirement datatype that is be sent to clients for generating PoW + |
Work | PoW datatype that clients send to server + |
Builder for Config
.
impl ConfigBuilder
pub fn salt(&mut self, value: String) -> &mut ConfigBuilder
pub fn build(&self) -> Result<Config, ConfigBuilderError>
impl Clone for ConfigBuilder
pub fn clone(&self) -> ConfigBuilder
pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl Default for ConfigBuilder
pub fn default() -> ConfigBuilder
impl RefUnwindSafe for ConfigBuilder
[src]impl Send for ConfigBuilder
[src]impl Sync for ConfigBuilder
[src]impl Unpin for ConfigBuilder
[src]impl UnwindSafe for ConfigBuilder
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
PoW requirement datatype that is be sent to clients for generating PoW
+string: String
difficulty_factor: u32
impl PoWConfig
[src]impl Clone for PoWConfig
[src]impl Debug for PoWConfig
[src]impl<'de> Deserialize<'de> for PoWConfig
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl Serialize for PoWConfig
[src]impl RefUnwindSafe for PoWConfig
[src]impl Send for PoWConfig
[src]impl Sync for PoWConfig
[src]impl Unpin for PoWConfig
[src]impl UnwindSafe for PoWConfig
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
PoW datatype that clients send to server
+string: String
result: String
nonce: u64
key: String
impl Clone for Work
[src]impl Debug for Work
[src]impl<'de> Deserialize<'de> for Work
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl Serialize for Work
[src]impl RefUnwindSafe for Work
[src]impl Send for Work
[src]impl Sync for Work
[src]impl Unpin for Work
[src]impl UnwindSafe for Work
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
module describing mCaptcha system
+System | struct describing various bits of data required for an mCaptcha system + |
SystemBuilder | Builder for |
struct describing various bits of data required for an mCaptcha system
+master: Addr<Master>
impl<T> System<T> where
T: Save,
<T as Actor>::Context: ToEnvelope<T, CachePoW> + ToEnvelope<T, RetrivePoW> + ToEnvelope<T, CacheResult> + ToEnvelope<T, VerifyCaptchaResult>,
[src]pub async fn get_pow(&self, id: String) -> Option<PoWConfig>
[src]utility function to get difficulty factor of site id
and cache it
pub async fn verify_pow(&self, work: Work) -> CaptchaResult<String>
[src]utility function to verify Work
+pub async fn validate_verification_tokens(
&self,
msg: VerifyCaptchaResult
) -> CaptchaResult<bool>
[src]utility function to validate verification tokens
+impl<T> !RefUnwindSafe for System<T>
[src]impl<T> Send for System<T>
[src]impl<T> Sync for System<T>
[src]impl<T> Unpin for System<T>
[src]impl<T> !UnwindSafe for System<T>
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
Builder for System
.
impl<T: Save + Clone> SystemBuilder<T>
[src]pub fn master(&mut self, value: Addr<Master>) -> &mut Self
[src]pub fn cache(&mut self, value: Addr<T>) -> &mut Self
[src]pub fn pow(&mut self, value: Config) -> &mut Self
[src]pub fn build(&self) -> Result<System<T>, String>
[src]impl<T: Clone + Save> Clone for SystemBuilder<T>
[src]fn clone(&self) -> SystemBuilder<T>
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl<T: Default + Save> Default for SystemBuilder<T>
[src]fn default() -> SystemBuilder<T>
[src]impl<T> !RefUnwindSafe for SystemBuilder<T>
[src]impl<T> Send for SystemBuilder<T>
[src]impl<T> Sync for SystemBuilder<T>
[src]impl<T> Unpin for SystemBuilder<T>
[src]impl<T> !UnwindSafe for SystemBuilder<T>
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
+pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]impl<V, T> VZip<V> for T where
V: MultiLane<T>,
pub fn vzip(self) -> V
"+""+(item.is_alias===true?(""+item.alias+" - see "):"")+item.displayPath+""+name+" | "+""+""+item.desc+" |
"+code.outerHTML+" |
fn:
) to \
+ restrict the search to a given item kind.","Accepted kinds are: fn
, mod
, struct
, \
+ enum
, trait
, type
, macro
, \
+ and const
.","Search functions by type signature (e.g., vec -> usize
or \
+ * -> vec
)","Search multiple things at once by splitting your query with comma (e.g., \
+ str,u8
or String,struct:Vec,test
)","You can look for items with an exact name by putting double quotes around \
+ your request: \"string\"
","Look for items inside another one by searching for a path: vec::Vec
",].map(x=>""+x+"
").join("");var div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="#[cfg]
if-else statements.","i":[[14,"cfg_if","cfg_if","The main macro provided by this crate. See crate …",null,null]],"p":[]},\
+"m_captcha":{"doc":"mCaptcha is a proof of work based Denaial-of-Service …","i":[[0,"defense","m_captcha","Defense datatypes",null,null],[3,"Level","m_captcha::defense","Level struct that describes threshold-difficulty factor …",null,null],[12,"visitor_threshold","","",0,null],[12,"difficulty_factor","","",0,null],[3,"LevelBuilder","","Bulder struct for [Level] to describe …",null,null],[11,"visitor_threshold","","set visitor count for level",1,[[["u32",15]]]],[11,"difficulty_factor","","set difficulty factor for level. difficulty_factor can\'t …",1,[[["u32",15]],["captcharesult",6]]],[11,"build","","build Level struct",1,[[],[["level",3],["captcharesult",6]]]],[3,"Defense","","struct describes all the different [Level]s at which an …",null,null],[3,"DefenseBuilder","","Builder struct for [Defense]",null,null],[11,"add_level","","add a level to [Defense]",2,[[["level",3]],["captcharesult",6]]],[11,"build","","Build [Defense]",2,[[],[["defense",3],["captcharesult",6]]]],[11,"get_difficulty","","! Difficulty is calculated as: ! …",3,[[],["u32",15]]],[11,"tighten_up","","tighten up defense. Increases defense level by a factor …",3,[[]]],[11,"loosen_up","","Loosen up defense. Decreases defense level by a factor of …",3,[[]]],[11,"max_defense","","Set defense to maximum level",3,[[]]],[11,"min_defense","","Set defense to minimum level",3,[[]]],[11,"visitor_threshold","","Get current level\'s visitor threshold",3,[[],["u32",15]]],[0,"errors","m_captcha","Errors and Result module",null,null],[4,"CaptchaError","m_captcha::errors","Error datatype",null,null],[13,"LevelEmpty","","When configuring m_captcha, [DefenseBuilder][…",4,null],[13,"DifficultyFactorZero","","Visitor count must be a whole number(zero and above). …",4,null],[13,"CaptchaDurationZero","","captcha cooldown duration must be greater than 0",4,null],[13,"SetDifficultyFactor","","Difficulty factor must be set",4,null],[13,"SetVisitorThreshold","","Visitor threshold must be set",4,null],[13,"DuplicateVisitorCount","","Visitor count must be Unique",4,null],[13,"DecreaseingDifficultyFactor","","Difficulty factor should increase with level",4,null],[13,"MailboxError","","Difficulty factor should increase with level",4,null],[13,"InsuffiencientDifficulty","","Happens when submitted work doesn\'t satisfy the required …",4,null],[13,"StringNotFound","","Happens when submitted work is computed over string that …",4,null],[13,"MCaptchaKeyValidationFail","","Happens when submitted work is computed over …",4,null],[13,"InvalidPoW","","Submitted PoW is invalid",4,null],[13,"PleaseSetValue","","Used in builder structs when a value is not set",4,null],[6,"CaptchaResult","","[Result] datatype for m_captcha",null,null],[0,"master","m_captcha","[Master] actor module that manages [MCaptcha] actors",null,null],[3,"Master","m_captcha::master","This Actor manages the [MCaptcha] actors. A service can …",null,null],[11,"add_site","","add [MCaptcha] actor to [Master]",5,[[["addsite",3]]]],[11,"new","","create new master accepts a u64
to configure garbage …",5,[[["u64",15]]]],[11,"get_site","","get [MCaptcha] actor from [Master]",5,[[["str",15]],[["option",4],["addr",3]]]],[11,"rm_site","","remvoes [MCaptcha] actor from [Master]",5,[[["str",15]]]],[3,"GetSite","","Message to get an [MCaptcha] actor from master",null,null],[12,"0","","",6,null],[3,"CleanUp","","Message to clean up master of [MCaptcha] actors with zero …",null,null],[3,"RemoveSite","","Message to delete [MCaptcha] actor",null,null],[12,"0","","",7,null],[3,"AddSite","","Message to add an [MCaptcha] actor to [Master]",null,null],[12,"id","","",8,null],[12,"addr","","",8,null],[3,"AddSiteBuilder","","Builder for AddSite
.",null,null],[11,"id","","",9,[[["string",3]]]],[11,"addr","","",9,[[["addr",3],["mcaptcha",3]]]],[11,"build","","Builds a new AddSite
.",9,[[],[["addsite",3],["string",3],["result",4]]]],[0,"mcaptcha","m_captcha","MCaptcha actor module that manages defense levels",null,null],[3,"MCaptchaBuilder","m_captcha::mcaptcha","Builder for [MCaptcha]",null,null],[3,"MCaptcha","","This struct represents the mCaptcha state and is used to …",null,null],[11,"defense","","set defense",10,[[["defense",3]]]],[11,"duration","","set duration",10,[[["u64",15]]]],[11,"build","","Builds new [MCaptcha]",10,[[],[["captcharesult",6],["mcaptcha",3]]]],[11,"add_visitor","","increments the visitor count by one",11,[[]]],[11,"decrement_visitor","","decrements the visitor count by one",11,[[]]],[11,"get_difficulty","","get current difficulty factor",11,[[],["u32",15]]],[11,"get_duration","","get [MCaptcha]\'s lifetime",11,[[],["u64",15]]],[3,"AddVisitor","","Message to increment the visitor count returns difficulty …",null,null],[3,"AddVisitorResult","","Struct representing the return datatime of [AddVisitor] …",null,null],[12,"duration","","",12,null],[12,"difficulty_factor","","",12,null],[3,"GetCurrentVisitorCount","","Message to get the visitor count",null,null],[3,"Stop","","Message to stop [MCaptcha]",null,null],[0,"cache","m_captcha","message datatypes to interact with [MCaptcha] actor Cache …",null,null],[0,"hashcache","m_captcha::cache","In-memory cache implementation that uses [HashMap]",null,null],[3,"HashCache","m_captcha::cache::hashcache","cache datastructure implementing [Save]",null,null],[0,"messages","m_captcha::cache","Messages that can be sent to cache data structures …",null,null],[3,"CachePoW","m_captcha::cache::messages","Message to cache PoW difficulty factor and string",null,null],[12,"string","","",13,null],[12,"difficulty_factor","","",13,null],[12,"duration","","",13,null],[12,"key","","",13,null],[3,"CachePoWBuilder","","Builder for CachePoW
.",null,null],[11,"string","","",14,[[["string",3]]]],[11,"difficulty_factor","","",14,[[["u32",15]]]],[11,"duration","","",14,[[["u64",15]]]],[11,"key","","",14,[[["string",3]]]],[11,"build","","Builds a new CachePoW
.",14,[[],[["result",4],["cachepow",3],["string",3]]]],[3,"RetrivePoW","","Message to retrive the the difficulty factor for the …",null,null],[12,"0","","",15,null],[3,"CachedPoWConfig","","",null,null],[12,"key","","",16,null],[12,"difficulty_factor","","",16,null],[12,"duration","","",16,null],[3,"DeletePoW","","Message to delete cached PoW difficulty factor and string …",null,null],[12,"0","","",17,null],[3,"CacheResult","","Message to cache captcha result and the captcha key for …",null,null],[12,"token","","",18,null],[12,"key","","",18,null],[12,"duration","","",18,null],[3,"CacheResultBuilder","","Builder for CacheResult
.",null,null],[11,"token","","",19,[[["string",3]]]],[11,"key","","",19,[[["string",3]]]],[11,"duration","","",19,[[["u64",15]]]],[11,"build","","Builds a new CacheResult
.",19,[[],[["result",4],["string",3],["cacheresult",3]]]],[3,"VerifyCaptchaResult","","Message to verify captcha result against the stored …",null,null],[12,"token","","",20,null],[12,"key","","",20,null],[3,"DeleteCaptchaResult","","Message to delete cached capthca result when it expires",null,null],[12,"token","","",21,null],[8,"Save","m_captcha::cache","Describes actor handler trait impls that are required by …",null,null],[0,"pow","m_captcha","PoW datatypes used in client-server interaction",null,null],[3,"ConfigBuilder","m_captcha::pow","Builder for Config
.",null,null],[3,"PoWConfig","","PoW requirement datatype that is be sent to clients for …",null,null],[12,"string","","",22,null],[12,"difficulty_factor","","",22,null],[11,"new","","create new instance of [PoWConfig]",22,[[["u32",15]]]],[3,"Work","","PoW datatype that clients send to server",null,null],[12,"string","","",23,null],[12,"result","","",23,null],[12,"nonce","","",23,null],[12,"key","","",23,null],[0,"system","m_captcha","module describing mCaptcha system",null,null],[3,"System","m_captcha::system","struct describing various bits of data required for an …",null,null],[12,"master","","",24,null],[3,"SystemBuilder","","Builder for System
.",null,null],[11,"master","","",25,[[["master",3],["addr",3]]]],[11,"cache","","",25,[[["addr",3]]]],[11,"pow","","",25,[[["config",3]]]],[11,"build","","Builds a new System
.",25,[[],[["result",4],["system",3],["string",3]]]],[11,"get_pow","","utility function to get difficulty factor of site id
and …",24,[[["string",3]]]],[11,"verify_pow","","utility function to verify [Work]",24,[[["work",3]]]],[11,"validate_verification_tokens","","utility function to validate verification tokens",24,[[["verifycaptcharesult",3]]]],[11,"from","m_captcha::defense","",0,[[]]],[11,"into","","",0,[[]]],[11,"to_owned","","",0,[[]]],[11,"clone_into","","",0,[[]]],[11,"borrow","","",0,[[]]],[11,"borrow_mut","","",0,[[]]],[11,"try_from","","",0,[[],["result",4]]],[11,"try_into","","",0,[[],["result",4]]],[11,"type_id","","",0,[[],["typeid",3]]],[11,"vzip","","",0,[[]]],[11,"from","","",1,[[]]],[11,"into","","",1,[[]]],[11,"to_owned","","",1,[[]]],[11,"clone_into","","",1,[[]]],[11,"borrow","","",1,[[]]],[11,"borrow_mut","","",1,[[]]],[11,"try_from","","",1,[[],["result",4]]],[11,"try_into","","",1,[[],["result",4]]],[11,"type_id","","",1,[[],["typeid",3]]],[11,"vzip","","",1,[[]]],[11,"from","","",3,[[]]],[11,"into","","",3,[[]]],[11,"to_owned","","",3,[[]]],[11,"clone_into","","",3,[[]]],[11,"borrow","","",3,[[]]],[11,"borrow_mut","","",3,[[]]],[11,"try_from","","",3,[[],["result",4]]],[11,"try_into","","",3,[[],["result",4]]],[11,"type_id","","",3,[[],["typeid",3]]],[11,"vzip","","",3,[[]]],[11,"from","","",2,[[]]],[11,"into","","",2,[[]]],[11,"to_owned","","",2,[[]]],[11,"clone_into","","",2,[[]]],[11,"borrow","","",2,[[]]],[11,"borrow_mut","","",2,[[]]],[11,"try_from","","",2,[[],["result",4]]],[11,"try_into","","",2,[[],["result",4]]],[11,"type_id","","",2,[[],["typeid",3]]],[11,"vzip","","",2,[[]]],[11,"from","m_captcha::errors","",4,[[]]],[11,"into","","",4,[[]]],[11,"to_owned","","",4,[[]]],[11,"clone_into","","",4,[[]]],[11,"to_string","","",4,[[],["string",3]]],[11,"borrow","","",4,[[]]],[11,"borrow_mut","","",4,[[]]],[11,"try_from","","",4,[[],["result",4]]],[11,"try_into","","",4,[[],["result",4]]],[11,"type_id","","",4,[[],["typeid",3]]],[11,"vzip","","",4,[[]]],[11,"from","m_captcha::master","",5,[[]]],[11,"into","","",5,[[]]],[11,"to_owned","","",5,[[]]],[11,"clone_into","","",5,[[]]],[11,"borrow","","",5,[[]]],[11,"borrow_mut","","",5,[[]]],[11,"try_from","","",5,[[],["result",4]]],[11,"try_into","","",5,[[],["result",4]]],[11,"type_id","","",5,[[],["typeid",3]]],[11,"vzip","","",5,[[]]],[11,"from","","",6,[[]]],[11,"into","","",6,[[]]],[11,"borrow","","",6,[[]]],[11,"borrow_mut","","",6,[[]]],[11,"try_from","","",6,[[],["result",4]]],[11,"try_into","","",6,[[],["result",4]]],[11,"type_id","","",6,[[],["typeid",3]]],[11,"vzip","","",6,[[]]],[11,"from","","",26,[[]]],[11,"into","","",26,[[]]],[11,"borrow","","",26,[[]]],[11,"borrow_mut","","",26,[[]]],[11,"try_from","","",26,[[],["result",4]]],[11,"try_into","","",26,[[],["result",4]]],[11,"type_id","","",26,[[],["typeid",3]]],[11,"vzip","","",26,[[]]],[11,"from","","",7,[[]]],[11,"into","","",7,[[]]],[11,"borrow","","",7,[[]]],[11,"borrow_mut","","",7,[[]]],[11,"try_from","","",7,[[],["result",4]]],[11,"try_into","","",7,[[],["result",4]]],[11,"type_id","","",7,[[],["typeid",3]]],[11,"vzip","","",7,[[]]],[11,"from","","",8,[[]]],[11,"into","","",8,[[]]],[11,"borrow","","",8,[[]]],[11,"borrow_mut","","",8,[[]]],[11,"try_from","","",8,[[],["result",4]]],[11,"try_into","","",8,[[],["result",4]]],[11,"type_id","","",8,[[],["typeid",3]]],[11,"vzip","","",8,[[]]],[11,"from","","",9,[[]]],[11,"into","","",9,[[]]],[11,"to_owned","","",9,[[]]],[11,"clone_into","","",9,[[]]],[11,"borrow","","",9,[[]]],[11,"borrow_mut","","",9,[[]]],[11,"try_from","","",9,[[],["result",4]]],[11,"try_into","","",9,[[],["result",4]]],[11,"type_id","","",9,[[],["typeid",3]]],[11,"vzip","","",9,[[]]],[11,"from","m_captcha::mcaptcha","",10,[[]]],[11,"into","","",10,[[]]],[11,"to_owned","","",10,[[]]],[11,"clone_into","","",10,[[]]],[11,"borrow","","",10,[[]]],[11,"borrow_mut","","",10,[[]]],[11,"try_from","","",10,[[],["result",4]]],[11,"try_into","","",10,[[],["result",4]]],[11,"type_id","","",10,[[],["typeid",3]]],[11,"vzip","","",10,[[]]],[11,"from","","",11,[[]]],[11,"into","","",11,[[]]],[11,"to_owned","","",11,[[]]],[11,"clone_into","","",11,[[]]],[11,"borrow","","",11,[[]]],[11,"borrow_mut","","",11,[[]]],[11,"try_from","","",11,[[],["result",4]]],[11,"try_into","","",11,[[],["result",4]]],[11,"type_id","","",11,[[],["typeid",3]]],[11,"vzip","","",11,[[]]],[11,"from","","",27,[[]]],[11,"into","","",27,[[]]],[11,"borrow","","",27,[[]]],[11,"borrow_mut","","",27,[[]]],[11,"try_from","","",27,[[],["result",4]]],[11,"try_into","","",27,[[],["result",4]]],[11,"type_id","","",27,[[],["typeid",3]]],[11,"vzip","","",27,[[]]],[11,"from","","",12,[[]]],[11,"into","","",12,[[]]],[11,"to_owned","","",12,[[]]],[11,"clone_into","","",12,[[]]],[11,"borrow","","",12,[[]]],[11,"borrow_mut","","",12,[[]]],[11,"try_from","","",12,[[],["result",4]]],[11,"try_into","","",12,[[],["result",4]]],[11,"type_id","","",12,[[],["typeid",3]]],[11,"vzip","","",12,[[]]],[11,"from","","",28,[[]]],[11,"into","","",28,[[]]],[11,"borrow","","",28,[[]]],[11,"borrow_mut","","",28,[[]]],[11,"try_from","","",28,[[],["result",4]]],[11,"try_into","","",28,[[],["result",4]]],[11,"type_id","","",28,[[],["typeid",3]]],[11,"vzip","","",28,[[]]],[11,"from","","",29,[[]]],[11,"into","","",29,[[]]],[11,"borrow","","",29,[[]]],[11,"borrow_mut","","",29,[[]]],[11,"try_from","","",29,[[],["result",4]]],[11,"try_into","","",29,[[],["result",4]]],[11,"type_id","","",29,[[],["typeid",3]]],[11,"vzip","","",29,[[]]],[11,"from","m_captcha::cache::hashcache","",30,[[]]],[11,"into","","",30,[[]]],[11,"to_owned","","",30,[[]]],[11,"clone_into","","",30,[[]]],[11,"borrow","","",30,[[]]],[11,"borrow_mut","","",30,[[]]],[11,"try_from","","",30,[[],["result",4]]],[11,"try_into","","",30,[[],["result",4]]],[11,"type_id","","",30,[[],["typeid",3]]],[11,"vzip","","",30,[[]]],[11,"from","m_captcha::cache::messages","",13,[[]]],[11,"into","","",13,[[]]],[11,"to_owned","","",13,[[]]],[11,"clone_into","","",13,[[]]],[11,"borrow","","",13,[[]]],[11,"borrow_mut","","",13,[[]]],[11,"try_from","","",13,[[],["result",4]]],[11,"try_into","","",13,[[],["result",4]]],[11,"type_id","","",13,[[],["typeid",3]]],[11,"vzip","","",13,[[]]],[11,"from","","",14,[[]]],[11,"into","","",14,[[]]],[11,"to_owned","","",14,[[]]],[11,"clone_into","","",14,[[]]],[11,"borrow","","",14,[[]]],[11,"borrow_mut","","",14,[[]]],[11,"try_from","","",14,[[],["result",4]]],[11,"try_into","","",14,[[],["result",4]]],[11,"type_id","","",14,[[],["typeid",3]]],[11,"vzip","","",14,[[]]],[11,"from","","",15,[[]]],[11,"into","","",15,[[]]],[11,"borrow","","",15,[[]]],[11,"borrow_mut","","",15,[[]]],[11,"try_from","","",15,[[],["result",4]]],[11,"try_into","","",15,[[],["result",4]]],[11,"type_id","","",15,[[],["typeid",3]]],[11,"vzip","","",15,[[]]],[11,"from","","",16,[[]]],[11,"into","","",16,[[]]],[11,"to_owned","","",16,[[]]],[11,"clone_into","","",16,[[]]],[11,"borrow","","",16,[[]]],[11,"borrow_mut","","",16,[[]]],[11,"try_from","","",16,[[],["result",4]]],[11,"try_into","","",16,[[],["result",4]]],[11,"type_id","","",16,[[],["typeid",3]]],[11,"vzip","","",16,[[]]],[11,"from","","",17,[[]]],[11,"into","","",17,[[]]],[11,"borrow","","",17,[[]]],[11,"borrow_mut","","",17,[[]]],[11,"try_from","","",17,[[],["result",4]]],[11,"try_into","","",17,[[],["result",4]]],[11,"type_id","","",17,[[],["typeid",3]]],[11,"vzip","","",17,[[]]],[11,"from","","",18,[[]]],[11,"into","","",18,[[]]],[11,"borrow","","",18,[[]]],[11,"borrow_mut","","",18,[[]]],[11,"try_from","","",18,[[],["result",4]]],[11,"try_into","","",18,[[],["result",4]]],[11,"type_id","","",18,[[],["typeid",3]]],[11,"vzip","","",18,[[]]],[11,"from","","",19,[[]]],[11,"into","","",19,[[]]],[11,"to_owned","","",19,[[]]],[11,"clone_into","","",19,[[]]],[11,"borrow","","",19,[[]]],[11,"borrow_mut","","",19,[[]]],[11,"try_from","","",19,[[],["result",4]]],[11,"try_into","","",19,[[],["result",4]]],[11,"type_id","","",19,[[],["typeid",3]]],[11,"vzip","","",19,[[]]],[11,"from","","",20,[[]]],[11,"into","","",20,[[]]],[11,"to_owned","","",20,[[]]],[11,"clone_into","","",20,[[]]],[11,"borrow","","",20,[[]]],[11,"borrow_mut","","",20,[[]]],[11,"try_from","","",20,[[],["result",4]]],[11,"try_into","","",20,[[],["result",4]]],[11,"type_id","","",20,[[],["typeid",3]]],[11,"vzip","","",20,[[]]],[11,"from","","",21,[[]]],[11,"into","","",21,[[]]],[11,"borrow","","",21,[[]]],[11,"borrow_mut","","",21,[[]]],[11,"try_from","","",21,[[],["result",4]]],[11,"try_into","","",21,[[],["result",4]]],[11,"type_id","","",21,[[],["typeid",3]]],[11,"vzip","","",21,[[]]],[11,"from","m_captcha::pow","",31,[[]]],[11,"into","","",31,[[]]],[11,"to_owned","","",31,[[]]],[11,"clone_into","","",31,[[]]],[11,"borrow","","",31,[[]]],[11,"borrow_mut","","",31,[[]]],[11,"try_from","","",31,[[],["result",4]]],[11,"try_into","","",31,[[],["result",4]]],[11,"type_id","","",31,[[],["typeid",3]]],[11,"vzip","","",31,[[]]],[11,"from","","",22,[[]]],[11,"into","","",22,[[]]],[11,"to_owned","","",22,[[]]],[11,"clone_into","","",22,[[]]],[11,"borrow","","",22,[[]]],[11,"borrow_mut","","",22,[[]]],[11,"try_from","","",22,[[],["result",4]]],[11,"try_into","","",22,[[],["result",4]]],[11,"type_id","","",22,[[],["typeid",3]]],[11,"vzip","","",22,[[]]],[11,"from","","",23,[[]]],[11,"into","","",23,[[]]],[11,"to_owned","","",23,[[]]],[11,"clone_into","","",23,[[]]],[11,"borrow","","",23,[[]]],[11,"borrow_mut","","",23,[[]]],[11,"try_from","","",23,[[],["result",4]]],[11,"try_into","","",23,[[],["result",4]]],[11,"type_id","","",23,[[],["typeid",3]]],[11,"vzip","","",23,[[]]],[11,"from","m_captcha::system","",24,[[]]],[11,"into","","",24,[[]]],[11,"to_owned","","",24,[[]]],[11,"clone_into","","",24,[[]]],[11,"borrow","","",24,[[]]],[11,"borrow_mut","","",24,[[]]],[11,"try_from","","",24,[[],["result",4]]],[11,"try_into","","",24,[[],["result",4]]],[11,"type_id","","",24,[[],["typeid",3]]],[11,"vzip","","",24,[[]]],[11,"from","","",25,[[]]],[11,"into","","",25,[[]]],[11,"to_owned","","",25,[[]]],[11,"clone_into","","",25,[[]]],[11,"borrow","","",25,[[]]],[11,"borrow_mut","","",25,[[]]],[11,"try_from","","",25,[[],["result",4]]],[11,"try_into","","",25,[[],["result",4]]],[11,"type_id","","",25,[[],["typeid",3]]],[11,"vzip","","",25,[[]]],[11,"default","m_captcha::pow","",31,[[],["configbuilder",3]]],[11,"clone","","",31,[[],["configbuilder",3]]],[11,"from","m_captcha::cache::messages","",18,[[["cachedpowconfig",3]]]],[11,"clone","m_captcha::defense","",0,[[],["level",3]]],[11,"clone","","",1,[[],["levelbuilder",3]]],[11,"clone","","",3,[[],["defense",3]]],[11,"clone","","",2,[[],["defensebuilder",3]]],[11,"clone","m_captcha::errors","",4,[[],["captchaerror",4]]],[11,"clone","m_captcha::master","",5,[[],["master",3]]],[11,"clone","","",9,[[],["addsitebuilder",3]]],[11,"clone","m_captcha::mcaptcha","",10,[[],["mcaptchabuilder",3]]],[11,"clone","","",11,[[],["mcaptcha",3]]],[11,"clone","","",12,[[],["addvisitorresult",3]]],[11,"clone","m_captcha::cache::hashcache","",30,[[],["hashcache",3]]],[11,"clone","m_captcha::cache::messages","",14,[[],["cachepowbuilder",3]]],[11,"clone","","",13,[[],["cachepow",3]]],[11,"clone","","",16,[[],["cachedpowconfig",3]]],[11,"clone","","",19,[[],["cacheresultbuilder",3]]],[11,"clone","","",20,[[],["verifycaptcharesult",3]]],[11,"clone","m_captcha::pow","",22,[[],["powconfig",3]]],[11,"clone","","",23,[[],["work",3]]],[11,"clone","m_captcha::system","",24,[[],["system",3]]],[11,"clone","","",25,[[],["systembuilder",3]]],[11,"default","m_captcha::defense","",1,[[]]],[11,"default","","",2,[[]]],[11,"default","m_captcha::master","",9,[[],["addsitebuilder",3]]],[11,"default","m_captcha::mcaptcha","",10,[[]]],[11,"default","m_captcha::cache::hashcache","",30,[[],["hashcache",3]]],[11,"default","m_captcha::cache::messages","",14,[[],["cachepowbuilder",3]]],[11,"default","","",16,[[],["cachedpowconfig",3]]],[11,"default","","",19,[[],["cacheresultbuilder",3]]],[11,"default","m_captcha::system","",25,[[],["systembuilder",3]]],[11,"eq","m_captcha::defense","",0,[[["level",3]],["bool",15]]],[11,"ne","","",0,[[["level",3]],["bool",15]]],[11,"eq","","",1,[[["levelbuilder",3]],["bool",15]]],[11,"ne","","",1,[[["levelbuilder",3]],["bool",15]]],[11,"eq","","",3,[[["defense",3]],["bool",15]]],[11,"ne","","",3,[[["defense",3]],["bool",15]]],[11,"eq","","",2,[[["defensebuilder",3]],["bool",15]]],[11,"ne","","",2,[[["defensebuilder",3]],["bool",15]]],[11,"eq","m_captcha::errors","",4,[[["captchaerror",4]],["bool",15]]],[11,"ne","","",4,[[["captchaerror",4]],["bool",15]]],[11,"eq","m_captcha::cache::messages","",16,[[["cachedpowconfig",3]],["bool",15]]],[11,"ne","","",16,[[["cachedpowconfig",3]],["bool",15]]],[11,"fmt","m_captcha::defense","",0,[[["formatter",3]],["result",6]]],[11,"fmt","","",1,[[["formatter",3]],["result",6]]],[11,"fmt","","",3,[[["formatter",3]],["result",6]]],[11,"fmt","","",2,[[["formatter",3]],["result",6]]],[11,"fmt","m_captcha::errors","",4,[[["formatter",3]],["result",6]]],[11,"fmt","m_captcha::mcaptcha","",10,[[["formatter",3]],["result",6]]],[11,"fmt","","",11,[[["formatter",3]],["result",6]]],[11,"fmt","","",12,[[["formatter",3]],["result",6]]],[11,"fmt","m_captcha::cache::messages","",16,[[["formatter",3]],["result",6]]],[11,"fmt","m_captcha::pow","",22,[[["formatter",3]],["result",6]]],[11,"fmt","","",23,[[["formatter",3]],["result",6]]],[11,"fmt","m_captcha::errors","",4,[[["formatter",3]],["result",6]]],[11,"serialize","m_captcha::defense","",0,[[],["result",4]]],[11,"serialize","","",3,[[],["result",4]]],[11,"serialize","m_captcha::mcaptcha","",10,[[],["result",4]]],[11,"serialize","","",11,[[],["result",4]]],[11,"serialize","","",12,[[],["result",4]]],[11,"serialize","m_captcha::cache::messages","",13,[[],["result",4]]],[11,"serialize","","",16,[[],["result",4]]],[11,"serialize","","",18,[[],["result",4]]],[11,"serialize","","",20,[[],["result",4]]],[11,"serialize","m_captcha::pow","",22,[[],["result",4]]],[11,"serialize","","",23,[[],["result",4]]],[11,"deserialize","m_captcha::defense","",0,[[],["result",4]]],[11,"deserialize","","",3,[[],["result",4]]],[11,"deserialize","m_captcha::mcaptcha","",10,[[],["result",4]]],[11,"deserialize","","",11,[[],["result",4]]],[11,"deserialize","","",12,[[],["result",4]]],[11,"deserialize","m_captcha::cache::messages","",13,[[],["result",4]]],[11,"deserialize","","",16,[[],["result",4]]],[11,"deserialize","","",18,[[],["result",4]]],[11,"deserialize","","",20,[[],["result",4]]],[11,"deserialize","m_captcha::pow","",22,[[],["result",4]]],[11,"deserialize","","",23,[[],["result",4]]],[11,"started","m_captcha::master","",5,[[]]],[11,"handle","","",5,[[["getsite",3]]]],[11,"handle","","",5,[[["cleanup",3]]]],[11,"handle","","",5,[[["removesite",3]]]],[11,"handle","","",5,[[["addsite",3]]]],[11,"handle","m_captcha::mcaptcha","",11,[[["addvisitor",3]]]],[11,"handle","","",11,[[["getcurrentvisitorcount",3]]]],[11,"handle","","",11,[[["stop",3]]]],[11,"handle","m_captcha::cache::hashcache","",30,[[["cachepow",3]]]],[11,"handle","","",30,[[["deletepow",3]]]],[11,"handle","","",30,[[["retrivepow",3]]]],[11,"handle","","",30,[[["cacheresult",3]]]],[11,"handle","","",30,[[["deletecaptcharesult",3]]]],[11,"handle","","",30,[[["verifycaptcharesult",3]]]],[11,"salt","m_captcha::pow","",31,[[["string",3]],["configbuilder",3]]],[11,"build","","Builds a new Config
.",31,[[],[["result",4],["config",3],["configbuildererror",4]]]]],"p":[[3,"Level"],[3,"LevelBuilder"],[3,"DefenseBuilder"],[3,"Defense"],[4,"CaptchaError"],[3,"Master"],[3,"GetSite"],[3,"RemoveSite"],[3,"AddSite"],[3,"AddSiteBuilder"],[3,"MCaptchaBuilder"],[3,"MCaptcha"],[3,"AddVisitorResult"],[3,"CachePoW"],[3,"CachePoWBuilder"],[3,"RetrivePoW"],[3,"CachedPoWConfig"],[3,"DeletePoW"],[3,"CacheResult"],[3,"CacheResultBuilder"],[3,"VerifyCaptchaResult"],[3,"DeleteCaptchaResult"],[3,"PoWConfig"],[3,"Work"],[3,"System"],[3,"SystemBuilder"],[3,"CleanUp"],[3,"AddVisitor"],[3,"GetCurrentVisitorCount"],[3,"Stop"],[3,"HashCache"],[3,"ConfigBuilder"]]},\
+"unicode_xid":{"doc":"Determine if a char
is a valid identifier for a parser …","i":[[17,"UNICODE_VERSION","unicode_xid","The version of Unicode that this version of unicode-xid …",null,null],[8,"UnicodeXID","","Methods for determining if a character is a valid …",null,null],[10,"is_xid_start","","Returns whether the specified character satisfies the …",0,[[]]],[10,"is_xid_continue","","Returns whether the specified char
satisfies the …",0,[[]]]],"p":[[8,"UnicodeXID"]]}\
+}');
+addSearchOptions(searchIndex);initSearch(searchIndex);
\ No newline at end of file
diff --git a/static/api-docs/m_captcha/0.1.3/settings.css b/static/api-docs/m_captcha/0.1.3/settings.css
new file mode 100644
index 0000000..6709865
--- /dev/null
+++ b/static/api-docs/m_captcha/0.1.3/settings.css
@@ -0,0 +1 @@
+.setting-line{padding:5px;position:relative;}.setting-line>div{display:inline-block;vertical-align:top;font-size:17px;padding-top:2px;}.setting-line>.title{font-size:19px;width:100%;max-width:none;border-bottom:1px solid;}.toggle{position:relative;display:inline-block;width:45px;height:27px;margin-right:20px;}.toggle input{opacity:0;position:absolute;}.select-wrapper{float:right;position:relative;height:27px;min-width:25%;}.select-wrapper select{appearance:none;-moz-appearance:none;-webkit-appearance:none;background:none;border:2px solid #ccc;padding-right:28px;width:100%;}.select-wrapper img{pointer-events:none;position:absolute;right:0;bottom:0;background:#ccc;height:100%;width:28px;padding:0px 4px;}.select-wrapper select option{color:initial;}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;-webkit-transition:.3s;transition:.3s;}.slider:before{position:absolute;content:"";height:19px;width:19px;left:4px;bottom:4px;background-color:white;-webkit-transition:.3s;transition:.3s;}input:checked+.slider{background-color:#2196F3;}input:focus+.slider{box-shadow:0 0 0 2px #0a84ff,0 0 0 6px rgba(10,132,255,0.3);}input:checked+.slider:before{-webkit-transform:translateX(19px);-ms-transform:translateX(19px);transform:translateX(19px);}.setting-line>.sub-settings{padding-left:42px;width:100%;display:block;}
\ No newline at end of file
diff --git a/static/api-docs/m_captcha/0.1.3/settings.html b/static/api-docs/m_captcha/0.1.3/settings.html
new file mode 100644
index 0000000..4a32679
--- /dev/null
+++ b/static/api-docs/m_captcha/0.1.3/settings.html
@@ -0,0 +1,7 @@
+1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +
+//! A macro for defining `#[cfg]` if-else statements. +//! +//! The macro provided by this crate, `cfg_if`, is similar to the `if/elif` C +//! preprocessor macro by allowing definition of a cascade of `#[cfg]` cases, +//! emitting the implementation which matches first. +//! +//! This allows you to conveniently provide a long list `#[cfg]`'d blocks of code +//! without having to rewrite each clause multiple times. +//! +//! # Example +//! +//! ``` +//! cfg_if::cfg_if! { +//! if #[cfg(unix)] { +//! fn foo() { /* unix specific functionality */ } +//! } else if #[cfg(target_pointer_width = "32")] { +//! fn foo() { /* non-unix, 32-bit functionality */ } +//! } else { +//! fn foo() { /* fallback implementation */ } +//! } +//! } +//! +//! # fn main() {} +//! ``` + +#![no_std] +#![doc(html_root_url = "https://docs.rs/cfg-if")] +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] + +/// The main macro provided by this crate. See crate documentation for more +/// information. +#[macro_export] +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($meta:meta)] { $($tokens:tt)* } + ) else * else { + $($tokens2:tt)* + }) => { + $crate::cfg_if! { + @__items + () ; + $( ( ($meta) ($($tokens)*) ), )* + ( () ($($tokens2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($i_met:meta)] { $($i_tokens:tt)* } + $( + else if #[cfg($e_met:meta)] { $($e_tokens:tt)* } + )* + ) => { + $crate::cfg_if! { + @__items + () ; + ( ($i_met) ($($i_tokens)*) ), + $( ( ($e_met) ($($e_tokens)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($tokens:tt)*) ), $($rest:tt)*) => { + // Emit all items within one block, applying an appropriate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + #[cfg(all($($m,)* not(any($($not),*))))] $crate::cfg_if! { @__identity $($tokens)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + $crate::cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to make __apply work out right for different match types, + // because of how macros matching/expand stuff. + (@__identity $($tokens:tt)*) => { + $($tokens)* + }; +} + +#[cfg(test)] +mod tests { + cfg_if! { + if #[cfg(test)] { + use core::option::Option as Option2; + fn works1() -> Option2<u32> { Some(1) } + } else { + fn works1() -> Option<u32> { None } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works2() -> bool { false } + } else if #[cfg(test)] { + fn works2() -> bool { true } + } else { + fn works2() -> bool { false } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works3() -> bool { false } + } else { + fn works3() -> bool { true } + } + } + + cfg_if! { + if #[cfg(test)] { + use core::option::Option as Option3; + fn works4() -> Option3<u32> { Some(1) } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works5() -> bool { false } + } else if #[cfg(test)] { + fn works5() -> bool { true } + } + } + + #[test] + fn it_works() { + assert!(works1().is_some()); + assert!(works2()); + assert!(works3()); + assert!(works4().is_some()); + assert!(works5()); + } + + #[test] + #[allow(clippy::assertions_on_constants)] + fn test_usage_within_a_function() { + cfg_if! {if #[cfg(debug_assertions)] { + // we want to put more than one thing here to make sure that they + // all get configured properly. + assert!(cfg!(debug_assertions)); + assert_eq!(4, 2+2); + } else { + assert!(works1().is_some()); + assert_eq!(10, 5+5); + }} + } + + trait Trait { + fn blah(&self); + } + + #[allow(dead_code)] + struct Struct; + + impl Trait for Struct { + cfg_if! { + if #[cfg(feature = "blah")] { + fn blah(&self) { + unimplemented!(); + } + } else { + fn blah(&self) { + unimplemented!(); + } + } + } + } +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +
+/* + * mCaptcha - A proof of work based DoS protection system + * Copyright © 2021 Aravinth Manivannan <realravinth@batsense.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +//! In-memory cache implementation that uses [HashMap] +use std::collections::HashMap; + +use actix::prelude::*; + +use super::messages::*; +use super::Save; +use crate::errors::*; + +#[derive(Clone, Default)] +/// cache datastructure implementing [Save] +pub struct HashCache { + difficulty_map: HashMap<String, CachedPoWConfig>, + result_map: HashMap<String, String>, +} + +impl HashCache { + // save [PoWConfig] to cache + fn save_pow_config(&mut self, config: CachePoW) -> CaptchaResult<()> { + let challenge = config.string; + let config: CachedPoWConfig = CachedPoWConfig { + key: config.key, + difficulty_factor: config.difficulty_factor, + duration: config.duration, + }; + + self.difficulty_map.insert(challenge, config); + Ok(()) + } + + // retrive [PoWConfig] from cache. Deletes config post retrival + fn retrive_pow_config(&mut self, string: String) -> CaptchaResult<Option<CachedPoWConfig>> { + if let Some(difficulty_factor) = self.remove_pow_config(&string) { + Ok(Some(difficulty_factor.to_owned())) + } else { + Ok(None) + } + } + + // delete [PoWConfig] from cache + fn remove_pow_config(&mut self, string: &str) -> Option<CachedPoWConfig> { + self.difficulty_map.remove(string) + } + + // save captcha result + fn save_captcha_result(&mut self, res: CacheResult) -> CaptchaResult<()> { + self.result_map.insert(res.token, res.key); + Ok(()) + } + + // verify captcha result + fn verify_captcha_result(&mut self, challenge: VerifyCaptchaResult) -> CaptchaResult<bool> { + if let Some(captcha_id) = self.remove_cache_result(&challenge.token) { + if captcha_id == challenge.key { + return Ok(true); + } else { + return Ok(false); + } + } else { + Ok(false) + } + } + + // delete cache result + fn remove_cache_result(&mut self, string: &str) -> Option<String> { + self.result_map.remove(string) + } +} + +impl Save for HashCache {} + +impl Actor for HashCache { + type Context = Context<Self>; +} + +/// cache a PoWConfig +impl Handler<CachePoW> for HashCache { + type Result = MessageResult<CachePoW>; + fn handle(&mut self, msg: CachePoW, ctx: &mut Self::Context) -> Self::Result { + //use actix::clock::sleep; + use actix::clock::delay_for; + use std::time::Duration; + + let addr = ctx.address(); + let del_msg = DeletePoW(msg.string.clone()); + + let duration: Duration = Duration::new(msg.duration.clone(), 0); + let wait_for = async move { + //sleep(duration).await; + delay_for(duration).await; + addr.send(del_msg).await.unwrap().unwrap(); + } + .into_actor(self); + ctx.spawn(wait_for); + + MessageResult(self.save_pow_config(msg)) + } +} + +/// Delte a PoWConfig +impl Handler<DeletePoW> for HashCache { + type Result = MessageResult<DeletePoW>; + fn handle(&mut self, msg: DeletePoW, _ctx: &mut Self::Context) -> Self::Result { + self.remove_pow_config(&msg.0); + MessageResult(Ok(())) + } +} + +/// Retrive PoW difficulty_factor for a PoW string +impl Handler<RetrivePoW> for HashCache { + type Result = MessageResult<RetrivePoW>; + fn handle(&mut self, msg: RetrivePoW, _ctx: &mut Self::Context) -> Self::Result { + MessageResult(self.retrive_pow_config(msg.0)) + } +} + +/// cache PoW result +impl Handler<CacheResult> for HashCache { + type Result = MessageResult<CacheResult>; + fn handle(&mut self, msg: CacheResult, ctx: &mut Self::Context) -> Self::Result { + //use actix::clock::sleep; + use actix::clock::delay_for; + use std::time::Duration; + + let addr = ctx.address(); + let del_msg = DeleteCaptchaResult { + token: msg.token.clone(), + }; + + let duration: Duration = Duration::new(msg.duration.clone(), 0); + let wait_for = async move { + //sleep(duration).await; + delay_for(duration).await; + addr.send(del_msg).await.unwrap().unwrap(); + } + .into_actor(self); + ctx.spawn(wait_for); + + MessageResult(self.save_captcha_result(msg)) + } +} + +/// Delte a PoWConfig +impl Handler<DeleteCaptchaResult> for HashCache { + type Result = MessageResult<DeleteCaptchaResult>; + fn handle(&mut self, msg: DeleteCaptchaResult, _ctx: &mut Self::Context) -> Self::Result { + self.remove_cache_result(&msg.token); + MessageResult(Ok(())) + } +} + +/// Retrive PoW difficulty_factor for a PoW string +impl Handler<VerifyCaptchaResult> for HashCache { + type Result = MessageResult<VerifyCaptchaResult>; + fn handle(&mut self, msg: VerifyCaptchaResult, _ctx: &mut Self::Context) -> Self::Result { + // MessageResult(self.retrive(msg.0)) + MessageResult(self.verify_captcha_result(msg)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mcaptcha::AddVisitorResult; + use crate::pow::PoWConfig; + + // async fn sleep(time: u64) { + // //use actix::clock::sleep; + // use actix::clock::delay_for; + // use std::time::Duration; + + // let duration: Duration = Duration::new(time, 0); + // //sleep(duration).await; + // delay_for(duration).await; + // } + + #[actix_rt::test] + async fn hashcache_pow_cache_works() { + use actix::clock::delay_for; + use actix::clock::Duration; + + const DIFFICULTY_FACTOR: u32 = 54; + const DURATION: u64 = 5; + const KEY: &str = "mcaptchakey"; + let addr = HashCache::default().start(); + let pow: PoWConfig = PoWConfig::new(DIFFICULTY_FACTOR); + let visitor_result = AddVisitorResult { + difficulty_factor: DIFFICULTY_FACTOR, + duration: DURATION, + }; + let string = pow.string.clone(); + + let msg = CachePoWBuilder::default() + .string(pow.string.clone()) + .difficulty_factor(DIFFICULTY_FACTOR) + .duration(visitor_result.duration) + .key(KEY.into()) + .build() + .unwrap(); + + addr.send(msg).await.unwrap().unwrap(); + + let cache_difficulty_factor = addr + .send(RetrivePoW(string.clone())) + .await + .unwrap() + .unwrap(); + assert_eq!( + DIFFICULTY_FACTOR, + cache_difficulty_factor.unwrap().difficulty_factor + ); + + let duration: Duration = Duration::new(5, 0); + //sleep(DURATION + DURATION).await; + delay_for(duration + duration).await; + + let expired_string = addr.send(RetrivePoW(string)).await.unwrap().unwrap(); + assert_eq!(None, expired_string); + } + + #[actix_rt::test] + async fn hashcache_result_cache_works() { + use actix::clock::delay_for; + use actix::clock::Duration; + + const DURATION: u64 = 5; + const KEY: &str = "a"; + const RES: &str = "b"; + let addr = HashCache::default().start(); + // send value to cache + // send another value to cache for auto delete + // verify_captcha_result + // delete + // wait for timeout and verify_captcha_result against second value + + let add_cache = CacheResult { + key: KEY.into(), + token: RES.into(), + duration: DURATION, + }; + + addr.send(add_cache).await.unwrap().unwrap(); + + let verify_msg = VerifyCaptchaResult { + key: KEY.into(), + token: RES.into(), + }; + + assert!(addr.send(verify_msg).await.unwrap().unwrap()); + + let verify_msg = VerifyCaptchaResult { + key: "cz".into(), + token: RES.into(), + }; + assert!(!addr.send(verify_msg).await.unwrap().unwrap()); + + let duration: Duration = Duration::new(5, 0); + delay_for(duration + duration).await; + + let verify_msg = VerifyCaptchaResult { + key: KEY.into(), + token: RES.into(), + }; + assert!(!addr.send(verify_msg).await.unwrap().unwrap()); + } +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +
+/* + * mCaptcha - A proof of work based DoS protection system + * Copyright © 2021 Aravinth Manivannan <realravinth@batsense.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +//! Cache is used to save proofof work details and nonces to prevent replay attacks +//! and rainbow/dictionary attacks +pub use hashcache::HashCache; +use messages::*; + +pub mod hashcache; + +/// Describes actor handler trait impls that are required by a cache implementation +pub trait Save: + actix::Actor + + actix::Handler<RetrivePoW> + + actix::Handler<CachePoW> + + actix::Handler<DeletePoW> + + actix::Handler<CacheResult> + + actix::Handler<VerifyCaptchaResult> + + actix::Handler<DeleteCaptchaResult> +{ +} +pub mod messages { + //! Messages that can be sent to cache data structures implementing [Save][super::Save] + use actix::dev::*; + use derive_builder::Builder; + use serde::{Deserialize, Serialize}; + + use crate::errors::*; + + /// Message to cache PoW difficulty factor and string + #[derive(Message, Serialize, Deserialize, Builder, Clone)] + #[rtype(result = "CaptchaResult<()>")] + pub struct CachePoW { + pub string: String, + pub difficulty_factor: u32, + pub duration: u64, + pub key: String, + } + + // pub fn new(p: &PoWConfig, k: String, v: &AddVisitorResult) -> Self { + // CachePoWBuilder::default() + // .string(p.string.clone()) + // .difficulty_factor(v.difficulty_factor) + // .duration(v.duration) + // .key(k) + // .build() + // .unwrap() + // } + //} + + /// Message to retrive the the difficulty factor for the specified + /// string from the cache + #[derive(Message)] + #[rtype(result = "CaptchaResult<Option<CachedPoWConfig>>")] + pub struct RetrivePoW(pub String); + + #[derive(Clone, PartialEq, Debug, Default, Deserialize, Serialize)] + pub struct CachedPoWConfig { + pub key: String, + pub difficulty_factor: u32, + pub duration: u64, + } + + /// Message to delete cached PoW difficulty factor and string + /// when they expire + #[derive(Message)] + #[rtype(result = "CaptchaResult<()>")] + pub struct DeletePoW(pub String); + + /// Message to cache captcha result and the captcha key for which + /// it was generated + #[derive(Message, Serialize, Deserialize, Builder)] + #[rtype(result = "CaptchaResult<()>")] + pub struct CacheResult { + pub token: String, + // key is Captcha identifier + pub key: String, + pub duration: u64, + } + + impl From<CachedPoWConfig> for CacheResult { + fn from(c: CachedPoWConfig) -> Self { + use crate::utils::get_random; + + CacheResultBuilder::default() + .key(c.key) + .duration(c.duration) + .token(get_random(32)) + .build() + .unwrap() + } + } + + /// Message to verify captcha result against + /// the stored captcha key + #[derive(Message, Clone, Deserialize, Serialize)] + #[rtype(result = "CaptchaResult<bool>")] + pub struct VerifyCaptchaResult { + pub token: String, + pub key: String, + } + + /// Message to delete cached capthca result when it expires + #[derive(Message)] + #[rtype(result = "CaptchaResult<()>")] + pub struct DeleteCaptchaResult { + pub token: String, + } +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +
+/* + * mCaptcha - A proof of work based DoS protection system + * Copyright © 2021 Aravinth Manivannan <realravinth@batsense.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +//! Defense datatypes +//! ```rust +//! use m_captcha::{LevelBuilder, DefenseBuilder}; +//! DefenseBuilder::default() +//! .add_level( +//! LevelBuilder::default() +//! .visitor_threshold(50) +//! .difficulty_factor(50) +//! .unwrap() +//! .build() +//! .unwrap(), +//! ) +//! .unwrap() +//! .add_level( +//! LevelBuilder::default() +//! .visitor_threshold(500) +//! .difficulty_factor(500) +//! .unwrap() +//! .build() +//! .unwrap(), +//! ) +//! .unwrap() +//! .build() +//! .unwrap(); +//! ``` + +use crate::errors::*; +use serde::{Deserialize, Serialize}; + +/// Level struct that describes threshold-difficulty factor mapping +#[derive(Debug, Deserialize, Serialize, Copy, Clone, PartialEq)] +pub struct Level { + pub visitor_threshold: u32, + pub difficulty_factor: u32, +} + +/// Bulder struct for [Level] to describe threshold-difficulty factor mapping +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct LevelBuilder { + visitor_threshold: Option<u32>, + difficulty_factor: Option<u32>, +} + +impl Default for LevelBuilder { + fn default() -> Self { + LevelBuilder { + visitor_threshold: None, + difficulty_factor: None, + } + } +} + +impl LevelBuilder { + /// set visitor count for level + pub fn visitor_threshold(&mut self, visitor_threshold: u32) -> &mut Self { + self.visitor_threshold = Some(visitor_threshold); + self + } + + /// set difficulty factor for level. difficulty_factor can't be zero because + /// Difficulty is calculated as: + /// ```no_run + /// let difficulty_factor = 500; + /// let difficulty = u128::max_value() - u128::max_value() / difficulty_factor; + /// ``` + /// the higher the `difficulty_factor`, the higher the difficulty. + pub fn difficulty_factor(&mut self, difficulty_factor: u32) -> CaptchaResult<&mut Self> { + if difficulty_factor > 0 { + self.difficulty_factor = Some(difficulty_factor); + Ok(self) + } else { + Err(CaptchaError::DifficultyFactorZero) + } + } + + /// build Level struct + pub fn build(&mut self) -> CaptchaResult<Level> { + if self.visitor_threshold.is_none() { + Err(CaptchaError::SetVisitorThreshold) + } else if self.difficulty_factor.is_none() { + Err(CaptchaError::SetDifficultyFactor) + } else { + Ok(Level { + difficulty_factor: self.difficulty_factor.unwrap(), + visitor_threshold: self.visitor_threshold.unwrap(), + }) + } + } +} + +/// struct describes all the different [Level]s at which an mCaptcha system operates +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +pub struct Defense { + levels: Vec<Level>, + // index of current visitor threshold + current_visitor_threshold: usize, +} + +/// Builder struct for [Defense] +#[derive(Debug, Clone, PartialEq)] +pub struct DefenseBuilder { + levels: Vec<Level>, +} + +impl Default for DefenseBuilder { + fn default() -> Self { + DefenseBuilder { levels: vec![] } + } +} + +impl DefenseBuilder { + /// add a level to [Defense] + pub fn add_level(&mut self, level: Level) -> CaptchaResult<&mut Self> { + for i in self.levels.iter() { + if i.visitor_threshold == level.visitor_threshold { + return Err(CaptchaError::DuplicateVisitorCount); + } + } + self.levels.push(level); + Ok(self) + } + + /// Build [Defense] + pub fn build(&mut self) -> CaptchaResult<Defense> { + if !self.levels.is_empty() { + // sort levels to arrange in ascending order + self.levels.sort_by_key(|a| a.visitor_threshold); + + for level in self.levels.iter() { + if level.difficulty_factor == 0 { + return Err(CaptchaError::DifficultyFactorZero); + } + } + + // as visitor count increases, difficulty_factor too should increse + // if it decreses, an error must be thrown + for i in 0..self.levels.len() - 1 { + if self.levels[i].difficulty_factor > self.levels[i + 1].difficulty_factor { + return Err(CaptchaError::DecreaseingDifficultyFactor); + } + } + + Ok(Defense { + levels: self.levels.to_owned(), + current_visitor_threshold: 0, + }) + } else { + Err(CaptchaError::LevelEmpty) + } + } +} + +impl Defense { + ///! Difficulty is calculated as: + ///! ```rust + ///! let difficulty = u128::max_value() - u128::max_value() / difficulty_factor; + ///! ``` + ///! The higher the `difficulty_factor`, the higher the difficulty. + + /// Get difficulty factor of current level of defense + pub fn get_difficulty(&self) -> u32 { + self.levels[self.current_visitor_threshold].difficulty_factor + } + + /// tighten up defense. Increases defense level by a factor of one. + /// When defense is at max level, calling this method will have no effect + pub fn tighten_up(&mut self) { + if self.current_visitor_threshold != self.levels.len() - 1 { + self.current_visitor_threshold += 1; + } + } + /// Loosen up defense. Decreases defense level by a factor of one. + /// When defense is at the lowest level, calling this method will have no effect. + pub fn loosen_up(&mut self) { + if self.current_visitor_threshold != 0 { + self.current_visitor_threshold -= 1; + } + } + + /// Set defense to maximum level + pub fn max_defense(&mut self) { + self.current_visitor_threshold = self.levels.len() - 1; + } + + /// Set defense to minimum level + pub fn min_defense(&mut self) { + self.current_visitor_threshold = 0; + } + + /// Get current level's visitor threshold + pub fn visitor_threshold(&self) -> u32 { + self.levels[self.current_visitor_threshold].visitor_threshold + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn level_builder_works() { + let level = LevelBuilder::default() + .difficulty_factor(1) + .unwrap() + .visitor_threshold(0) + .build() + .unwrap(); + + assert_eq!(level.visitor_threshold, 0); + assert_eq!(level.difficulty_factor, 1); + + assert_eq!( + LevelBuilder::default().difficulty_factor(0), + Err(CaptchaError::DifficultyFactorZero) + ); + + assert_eq!( + LevelBuilder::default() + .difficulty_factor(1) + .unwrap() + .build(), + Err(CaptchaError::SetVisitorThreshold) + ); + assert_eq!( + LevelBuilder::default().visitor_threshold(10).build(), + Err(CaptchaError::SetDifficultyFactor) + ); + } + + #[test] + fn defense_builder_duplicate_visitor_threshold() { + let mut defense_builder = DefenseBuilder::default(); + let err = defense_builder + .add_level( + LevelBuilder::default() + .visitor_threshold(50) + .difficulty_factor(50) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .add_level( + LevelBuilder::default() + .visitor_threshold(50) + .difficulty_factor(50) + .unwrap() + .build() + .unwrap(), + ); + assert_eq!(err, Err(CaptchaError::DuplicateVisitorCount)); + } + + #[test] + fn defense_builder_decreasing_difficulty_factor() { + let mut defense_builder = DefenseBuilder::default(); + let err = defense_builder + .add_level( + LevelBuilder::default() + .visitor_threshold(50) + .difficulty_factor(50) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .add_level( + LevelBuilder::default() + .visitor_threshold(500) + .difficulty_factor(10) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .build(); + assert_eq!(err, Err(CaptchaError::DecreaseingDifficultyFactor)); + } + + fn get_defense() -> Defense { + DefenseBuilder::default() + .add_level( + LevelBuilder::default() + .visitor_threshold(50) + .difficulty_factor(50) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .add_level( + LevelBuilder::default() + .visitor_threshold(500) + .difficulty_factor(5000) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .add_level( + LevelBuilder::default() + .visitor_threshold(5000) + .difficulty_factor(50000) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .add_level( + LevelBuilder::default() + .visitor_threshold(50000) + .difficulty_factor(500000) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .add_level( + LevelBuilder::default() + .visitor_threshold(500000) + .difficulty_factor(5000000) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .build() + .unwrap() + } + #[test] + fn defense_builder_works() { + let defense = get_defense(); + + assert_eq!(defense.levels[0].difficulty_factor, 50); + assert_eq!(defense.levels[1].difficulty_factor, 5000); + assert_eq!(defense.levels[2].difficulty_factor, 50_000); + assert_eq!(defense.levels[3].difficulty_factor, 500_000); + assert_eq!(defense.levels[4].difficulty_factor, 5_000_000); + } + + #[test] + fn tighten_up_works() { + let mut defense = get_defense(); + + assert_eq!(defense.get_difficulty(), 50); + + defense.tighten_up(); + assert_eq!(defense.get_difficulty(), 5_000); + + defense.tighten_up(); + assert_eq!(defense.get_difficulty(), 50_000); + + defense.tighten_up(); + assert_eq!(defense.get_difficulty(), 500_000); + + defense.tighten_up(); + assert_eq!(defense.get_difficulty(), 5_000_000); + + defense.tighten_up(); + assert_eq!(defense.get_difficulty(), 5_000_000); + } + + #[test] + fn max_defense_works() { + let mut defense = get_defense(); + defense.max_defense(); + assert_eq!(defense.get_difficulty(), 5_000_000); + } + + #[test] + fn minimum_defense_works() { + let mut defense = get_defense(); + defense.min_defense(); + assert_eq!(defense.get_difficulty(), 50); + } + + #[test] + fn loosen_up_works() { + let mut defense = get_defense(); + defense.max_defense(); + + assert_eq!(defense.get_difficulty(), 5_000_000); + + defense.loosen_up(); + assert_eq!(defense.get_difficulty(), 500_000); + + defense.loosen_up(); + assert_eq!(defense.get_difficulty(), 50_000); + + defense.loosen_up(); + assert_eq!(defense.get_difficulty(), 5_000); + + defense.loosen_up(); + assert_eq!(defense.get_difficulty(), 50); + + defense.loosen_up(); + assert_eq!(defense.get_difficulty(), 50); + } +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +
+/* + * mCaptcha - A proof of work based DoS protection system + * Copyright © 2021 Aravinth Manivannan <realravinth@batsense.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +//! Errors and Result module +use derive_more::{Display, Error}; + +/// Error datatype +#[derive(Debug, PartialEq, Display, Clone, Error)] +#[cfg(not(tarpaulin_include))] +pub enum CaptchaError { + /// When configuring m_captcha, [DefenseBuilder][crate::defense::DefenseBuilder] + /// must be passed atleast one `LevelConfig` if not this error will arise + #[display(fmt = "LevelBuilder should have atleaset one level configured")] + LevelEmpty, + + /// Visitor count must be a whole number(zero and above). + /// When configuring m_captcha, [LevelBuilder][crate::defense::LevelBuilder]. + /// difficulty_factor must be set to greater than zero. + #[display(fmt = "difficulty factor must be greater than zero")] + DifficultyFactorZero, + + /// captcha cooldown duration must be greater than 0 + #[display(fmt = "difficulty factor must be greater than zero")] + CaptchaDurationZero, + + /// Difficulty factor must be set + #[display(fmt = "Set difficulty factor")] + SetDifficultyFactor, + + /// Visitor threshold must be set + #[display(fmt = "Set visitor threshold")] + SetVisitorThreshold, + + /// Visitor count must be Unique + #[display(fmt = "Duplicate visitor count")] + DuplicateVisitorCount, + + /// Difficulty factor should increase with level + #[display(fmt = "Difficulty factor should increase with level")] + DecreaseingDifficultyFactor, + + /// Difficulty factor should increase with level + #[display(fmt = "Actor mailbox error")] + MailboxError, + + /// Happens when submitted work doesn't satisfy the required + /// difficulty factor + #[display(fmt = "Insuffiencient Difficulty")] + InsuffiencientDifficulty, + + /// Happens when submitted work is computed over string that + /// isn't in cache + #[display(fmt = "String now found")] + StringNotFound, + + /// Happens when submitted work is computed over configuration intended for + /// a different mCAptcha sitekey + #[display(fmt = "PoW computed over configuration not intended for target sitekey")] + MCaptchaKeyValidationFail, + + /// Submitted PoW is invalid + #[display(fmt = "Invalid PoW")] + InvalidPoW, + + /// Used in builder structs when a value is not set + #[display(fmt = "Please set value: {}", _0)] + PleaseSetValue(#[error(not(source))] String), +} + +/// [Result] datatype for m_captcha +pub type CaptchaResult<V> = std::result::Result<V, CaptchaError>; +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +
+/* + * mCaptcha - A proof of work based DoS protection system + * Copyright © 2021 Aravinth Manivannan <realravinth@batsense.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +//! mCaptcha is a proof of work based Denaial-of-Service attack protection system. +//! This is is a server library that you can embed in your services to protect your +//! servers. +//! +//! A commercial managed solution is in the works but I'd much rather prefer +//! folks host their own instances as it will make the more decentralized and free. +//! +//! In mCaptcha, defense is adjusted in discrete levels that depend on the +//! ammount of traffic that a service is experiencing. So users of this library are +//! requested to benchmark their target machines before configuring their mCaptcha +//! component. +//! +//! ## Terminology: +//! - Difficulty(Factor): Minimum ammount of work that a client must do to make a valid +//! request. +//! - [Defense]: A datatype that various visitor-difficulty mappigns +//! - Visitor: Smallest unit of traffic, usually a single request. The more you have, the busier +//! your service is. Determines mCaptcha defense defense +//! - Visitor threshold: The threshold at which [MCaptcha] will adjust defense defense +//! - [Cache][crate::cache] : A datatype that implements [Save][crate::cache::Save]. Used to store +//! PoW requirements to defend against replay attacks and dictionary attacks. +//! - [Master][crate::master::Master]: A datatype that manages +//! [MCaptcha][crate::mcaptcha::MCaptcha] actors. Works like a DNS for +//! [AddVisitor][crate::mcaptcha::AddVisitor] messages. +//! - [System][crate::system::System]: mCaptcha system that manages cache, master and provides +//! useful abstractions. An mCaptcha system/instance can have only a single +//! [System][crate::system::System] +//! +//! ## Example: +//! +//! ```rust +//! use m_captcha::{ +//! cache::{messages::VerifyCaptchaResult, HashCache}, +//! master::{AddSiteBuilder, Master}, +//! pow::{ConfigBuilder, Work}, +//! system::SystemBuilder, +//! DefenseBuilder, LevelBuilder, MCaptchaBuilder, +//! }; +//! // traits from actix needs to be in scope for starting actor +//! use actix::prelude::*; +//! +//! #[actix_rt::main] +//! async fn main() -> std::io::Result<()> { +//! // start cahce actor +//! // cache is used to store PoW requirements that are sent to clients +//! // This way, it can be verified that the client computed work over a config +//! // that _we_ sent. Offers protection against rainbow tables powered dictionary attacks +//! let cache = HashCache::default().start(); +//! +//! // create PoW config with unique salt. Salt has to be safely guarded. +//! // salts protect us from replay attacks +//! let pow = ConfigBuilder::default() +//! .salt("myrandomsaltisnotlongenoug".into()) +//! .build() +//! .unwrap(); +//! +//! // start master actor. Master actor is responsible for managing MCaptcha actors +//! // each mCaptcha system should have only one master +//! let master = Master::new(5).start(); +//! +//! // Create system. System encapsulates master and cache and provides useful abstraction +//! // each mCaptcha system should have only one system +//! let system = SystemBuilder::default() +//! .master(master) +//! .cache(cache) +//! .pow(pow.clone()) +//! .build() +//! .unwrap(); +//! +//! // configure defense. This is a per site configuration. A site can have several levels +//! // of defenses configured +//! let defense = DefenseBuilder::default() +//! // add as many defense as you see fit +//! .add_level( +//! LevelBuilder::default() +//! // visitor_threshold is the threshold/limit at which +//! // mCaptcha will adjust difficulty defense +//! // it is advisable to set small values for the first +//! // defense visitor_threshold and difficulty_factor +//! // as this will be the work that clients will be +//! // computing when there's no load +//! .visitor_threshold(50) +//! .difficulty_factor(500) +//! .unwrap() +//! .build() +//! .unwrap(), +//! ) +//! .unwrap() +//! .add_level( +//! LevelBuilder::default() +//! .visitor_threshold(5000) +//! .difficulty_factor(50000) +//! .unwrap() +//! .build() +//! .unwrap(), +//! ) +//! .unwrap() +//! .build() +//! .unwrap(); +//! +//! // create and start MCaptcha actor that uses the above defense configuration +//! // This is what manages the difficulty factor of sites that an mCaptcha protects +//! let mcaptcha = MCaptchaBuilder::default() +//! .defense(defense) +//! // leaky bucket algorithm's emission interval +//! .duration(30) +//! // .cache(cache) +//! .build() +//! .unwrap() +//! .start(); +//! +//! // unique value identifying an MCaptcha actor +//! let mcaptcha_name = "batsense.net"; +//! +//! // add MCaptcha to Master +//! let msg = AddSiteBuilder::default() +//! .id(mcaptcha_name.into()) +//! .addr(mcaptcha.clone()) +//! .build() +//! .unwrap(); +//! system.master.send(msg).await.unwrap(); +//! +//! // Get PoW config. Should be called everytime there's a visitor for a +//! // managed site(here mcaptcha_name) +//! let work_req = system.get_pow(mcaptcha_name.into()).await.unwrap(); +//! +//! // the following computation should be done on the client but for the purpose +//! // of this illustration, we are going to do it on the server it self +//! let work = pow +//! .prove_work(&work_req.string, work_req.difficulty_factor) +//! .unwrap(); +//! +//! // the payload that the client sends to the server +//! let payload = Work { +//! string: work_req.string, +//! result: work.result, +//! nonce: work.nonce, +//! key: mcaptcha_name.into(), +//! }; +//! +//! // Server evaluates client's work. Returns true if everything +//! // checksout and Err() if something fishy is happening +//! let res = system.verify_pow(payload.clone()).await; +//! assert!(res.is_ok()); +//! +//! // The client should submit the token to the mCaptcha protected service +//! // The service should validate the token received from the client +//! // with the mCaptcha server before processing client's +//! // request +//! +//! // mcaptcha protected service sends the following paylaod to mCaptcha +//! // server: +//! let verify_msg = VerifyCaptchaResult { +//! token: res.unwrap(), +//! key: mcaptcha_name.into(), +//! }; +//! +//! // on mCaptcha server: +//! let res = system.validate_verification_tokens(verify_msg).await; +//! // mCaptcha will return true if token is valid and false if +//! // token is invalid +//! assert!(res.is_ok()); +//! assert!(res.unwrap()); +//! +//! Ok(()) +//! } +//! ``` +#![forbid(unsafe_code)] +pub mod defense; +pub mod errors; +pub mod master; +pub mod mcaptcha; + +/// message datatypes to interact with [MCaptcha] actor +pub mod cache; +pub mod pow; +pub mod system; +mod utils; + +pub use crate::cache::hashcache::HashCache; + +pub use defense::{Defense, DefenseBuilder, LevelBuilder}; +pub use mcaptcha::{MCaptcha, MCaptchaBuilder}; +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +
+/* + * mCaptcha - A proof of work based DoS protection system + * Copyright © 2021 Aravinth Manivannan <realravinth@batsense.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +//! [Master] actor module that manages [MCaptcha] actors +use std::collections::BTreeMap; +use std::time::Duration; + +//use actix::clock::sleep; +use actix::clock::delay_for; +use actix::dev::*; +use derive_builder::Builder; +use log::info; + +use crate::mcaptcha::MCaptcha; + +/// This Actor manages the [MCaptcha] actors. +/// A service can have several [MCaptcha] actors with +/// varying [Defense][crate::defense::Defense] configurations +/// so a "master" actor is needed to manage them all +#[derive(Clone)] +pub struct Master { + sites: BTreeMap<String, (Option<()>, Addr<MCaptcha>)>, + gc: u64, +} + +impl Master { + /// add [MCaptcha] actor to [Master] + pub fn add_site(&mut self, details: AddSite) { + self.sites + .insert(details.id, (None, details.addr.to_owned())); + } + + /// create new master + /// accepts a `u64` to configure garbage collection period + pub fn new(gc: u64) -> Self { + Master { + sites: BTreeMap::new(), + gc, + } + } + + /// get [MCaptcha] actor from [Master] + pub fn get_site<'a, 'b>(&'a mut self, id: &'b str) -> Option<Addr<MCaptcha>> { + let mut r = None; + if let Some((read_val, addr)) = self.sites.get_mut(id) { + r = Some(addr.clone()); + *read_val = Some(()); + }; + r + } + + /// remvoes [MCaptcha] actor from [Master] + pub fn rm_site(&mut self, id: &str) { + self.sites.remove(id); + } +} + +impl Actor for Master { + type Context = Context<Self>; + + fn started(&mut self, ctx: &mut Self::Context) { + let addr = ctx.address(); + let task = async move { + addr.send(CleanUp).await.unwrap(); + } + .into_actor(self); + ctx.spawn(task); + } +} + +/// Message to get an [MCaptcha] actor from master +#[derive(Message)] +#[rtype(result = "Option<Addr<MCaptcha>>")] +pub struct GetSite(pub String); + +impl Handler<GetSite> for Master { + type Result = MessageResult<GetSite>; + + fn handle(&mut self, m: GetSite, _ctx: &mut Self::Context) -> Self::Result { + let addr = self.get_site(&m.0); + if addr.is_none() { + return MessageResult(None); + } else { + return MessageResult(Some(addr.unwrap().clone())); + } + } +} + +/// Message to clean up master of [MCaptcha] actors with zero visitor count +#[derive(Message)] +#[rtype(result = "()")] +pub struct CleanUp; + +impl Handler<CleanUp> for Master { + type Result = (); + + fn handle(&mut self, _: CleanUp, ctx: &mut Self::Context) -> Self::Result { + let sites = self.sites.clone(); + let gc = self.gc; + let master = ctx.address(); + info!("init master actor cleanup up"); + let task = async move { + for (id, (new, addr)) in sites.iter() { + use crate::mcaptcha::{GetCurrentVisitorCount, Stop}; + let visitor_count = addr.send(GetCurrentVisitorCount).await.unwrap(); + println!("{}", visitor_count); + if visitor_count == 0 && new.is_some() { + addr.send(Stop).await.unwrap(); + master.send(RemoveSite(id.to_owned())).await.unwrap(); + println!("cleaned up"); + } + } + + let duration = Duration::new(gc, 0); + //sleep(duration).await; + delay_for(duration).await; + master.send(CleanUp).await.unwrap(); + } + .into_actor(self); + ctx.spawn(task); + } +} + +/// Message to delete [MCaptcha] actor +#[derive(Message)] +#[rtype(result = "()")] +pub struct RemoveSite(pub String); + +impl Handler<RemoveSite> for Master { + type Result = (); + + fn handle(&mut self, m: RemoveSite, _ctx: &mut Self::Context) -> Self::Result { + self.rm_site(&m.0); + } +} + +/// Message to add an [MCaptcha] actor to [Master] +#[derive(Message, Builder)] +#[rtype(result = "()")] +pub struct AddSite { + pub id: String, + pub addr: Addr<MCaptcha>, +} + +impl Handler<AddSite> for Master { + type Result = (); + + fn handle(&mut self, m: AddSite, _ctx: &mut Self::Context) -> Self::Result { + self.add_site(m); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mcaptcha::tests::*; + + #[actix_rt::test] + async fn master_actor_works() { + let addr = Master::new(1).start(); + + let id = "yo"; + let mcaptcha = get_counter().start(); + let msg = AddSiteBuilder::default() + .id(id.into()) + .addr(mcaptcha.clone()) + .build() + .unwrap(); + + addr.send(msg).await.unwrap(); + + let mcaptcha_addr = addr.send(GetSite(id.into())).await.unwrap(); + assert_eq!(mcaptcha_addr, Some(mcaptcha)); + + let addr_doesnt_exist = addr.send(GetSite("a".into())).await.unwrap(); + assert!(addr_doesnt_exist.is_none()); + + let timer_expire = Duration::new(DURATION, 0); + // sleep(timer_expire).await; + // sleep(timer_expire).await; + delay_for(timer_expire).await; + delay_for(timer_expire).await; + + let mcaptcha_addr = addr.send(GetSite(id.into())).await.unwrap(); + assert_eq!(mcaptcha_addr, None); + } +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +
+/* + * mCaptcha - A proof of work based DoS protection system + * Copyright © 2021 Aravinth Manivannan <realravinth@batsense.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +//! MCaptcha actor module that manages defense levels +//! +//! ## Usage: +//! ```rust +//! use m_captcha::{mcaptcha::AddVisitor, MCaptchaBuilder, cache::HashCache, LevelBuilder, DefenseBuilder}; +//! // traits from actix needs to be in scope for starting actor +//! use actix::prelude::*; +//! +//! #[actix_rt::main] +//! async fn main() -> std::io::Result<()> { +//! // configure defense +//! let defense = DefenseBuilder::default() +//! // add as many levels as you see fit +//! .add_level( +//! LevelBuilder::default() +//! // visitor_threshold is the threshold/limit at which +//! // mCaptcha will adjust difficulty levels +//! // it is advisable to set small values for the first +//! // levels visitor_threshold and difficulty_factor +//! // as this will be the work that clients will be +//! // computing when there's no load +//! .visitor_threshold(50) +//! .difficulty_factor(500) +//! .unwrap() +//! .build() +//! .unwrap(), +//! ) +//! .unwrap() +//! .add_level( +//! LevelBuilder::default() +//! .visitor_threshold(5000) +//! .difficulty_factor(50000) +//! .unwrap() +//! .build() +//! .unwrap(), +//! ) +//! .unwrap() +//! .build() +//! .unwrap(); +//! +//! // create and start MCaptcha actor +//! //let cache = HashCache::default().start(); +//! let mcaptcha = MCaptchaBuilder::default() +//! .defense(defense) +//! // leaky bucket algorithm's emission interval +//! .duration(30) +//! .build() +//! .unwrap() +//! .start(); +//! +//! // increment count when user visits protected routes +//! mcaptcha.send(AddVisitor).await.unwrap(); +//! +//! Ok(()) +//! } +//! ``` + +use std::time::Duration; + +//use actix::clock::sleep; +use actix::dev::*; +use serde::{Deserialize, Serialize}; + +use crate::{ + defense::Defense, + errors::{CaptchaError, CaptchaResult}, +}; + +/// Builder for [MCaptcha] +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct MCaptchaBuilder { + visitor_threshold: u32, + defense: Option<Defense>, + duration: Option<u64>, +} + +impl Default for MCaptchaBuilder { + fn default() -> Self { + MCaptchaBuilder { + visitor_threshold: 0, + defense: None, + duration: None, + } + } +} + +/// This struct represents the mCaptcha state and is used +/// to configure leaky-bucket lifetime and manage defense +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct MCaptcha { + visitor_threshold: u32, + defense: Defense, + duration: u64, +} + +impl MCaptchaBuilder { + /// set defense + pub fn defense(&mut self, d: Defense) -> &mut Self { + self.defense = Some(d); + self + } + + /// set duration + pub fn duration(&mut self, d: u64) -> &mut Self { + self.duration = Some(d); + self + } + + /// Builds new [MCaptcha] + pub fn build(&mut self) -> CaptchaResult<MCaptcha> { + if self.duration.is_none() { + Err(CaptchaError::PleaseSetValue("duration".into())) + } else if self.defense.is_none() { + Err(CaptchaError::PleaseSetValue("defense".into())) + } else if self.duration <= Some(0) { + Err(CaptchaError::CaptchaDurationZero) + } else { + let m = MCaptcha { + duration: self.duration.unwrap(), + defense: self.defense.clone().unwrap(), + visitor_threshold: self.visitor_threshold, + }; + Ok(m) + } + } +} + +impl MCaptcha { + /// increments the visitor count by one + pub fn add_visitor(&mut self) { + self.visitor_threshold += 1; + if self.visitor_threshold > self.defense.visitor_threshold() { + self.defense.tighten_up(); + } else { + self.defense.loosen_up(); + } + } + + /// decrements the visitor count by one + pub fn decrement_visitor(&mut self) { + if self.visitor_threshold > 0 { + self.visitor_threshold -= 1; + } + } + + /// get current difficulty factor + pub fn get_difficulty(&self) -> u32 { + self.defense.get_difficulty() + } + + /// get [MCaptcha]'s lifetime + pub fn get_duration(&self) -> u64 { + self.duration + } +} +impl Actor for MCaptcha { + type Context = Context<Self>; +} + +/// Message to decrement the visitor count +#[derive(Message)] +#[rtype(result = "()")] +struct DeleteVisitor; + +impl Handler<DeleteVisitor> for MCaptcha { + type Result = (); + fn handle(&mut self, _msg: DeleteVisitor, _ctx: &mut Self::Context) -> Self::Result { + self.decrement_visitor(); + } +} + +/// Message to increment the visitor count +/// returns difficulty factor and lifetime +#[derive(Message)] +#[rtype(result = "AddVisitorResult")] +pub struct AddVisitor; + +/// Struct representing the return datatime of +/// [AddVisitor] message. Contains MCaptcha lifetime +/// and difficulty factor +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct AddVisitorResult { + pub duration: u64, + pub difficulty_factor: u32, +} + +impl AddVisitorResult { + fn new(m: &MCaptcha) -> Self { + AddVisitorResult { + duration: m.get_duration(), + difficulty_factor: m.get_difficulty(), + } + } +} + +impl Handler<AddVisitor> for MCaptcha { + type Result = MessageResult<AddVisitor>; + + fn handle(&mut self, _: AddVisitor, ctx: &mut Self::Context) -> Self::Result { + let addr = ctx.address(); + use actix::clock::delay_for; + + let duration: Duration = Duration::new(self.duration.clone(), 0); + let wait_for = async move { + //sleep(duration).await; + delay_for(duration).await; + addr.send(DeleteVisitor).await.unwrap(); + } + .into_actor(self); + ctx.spawn(wait_for); + + self.add_visitor(); + MessageResult(AddVisitorResult::new(&self)) + } +} + +/// Message to get the visitor count +#[derive(Message)] +#[rtype(result = "u32")] +pub struct GetCurrentVisitorCount; + +impl Handler<GetCurrentVisitorCount> for MCaptcha { + type Result = MessageResult<GetCurrentVisitorCount>; + + fn handle(&mut self, _: GetCurrentVisitorCount, _ctx: &mut Self::Context) -> Self::Result { + MessageResult(self.visitor_threshold) + } +} + +/// Message to stop [MCaptcha] +#[derive(Message)] +#[rtype(result = "()")] +pub struct Stop; + +impl Handler<Stop> for MCaptcha { + type Result = (); + + fn handle(&mut self, _: Stop, ctx: &mut Self::Context) -> Self::Result { + ctx.stop() + } +} + +#[cfg(test)] +pub mod tests { + use super::*; + use crate::defense::*; + + // constants for testing + // (visitor count, level) + pub const LEVEL_1: (u32, u32) = (50, 50); + pub const LEVEL_2: (u32, u32) = (500, 500); + pub const DURATION: u64 = 5; + + type MyActor = Addr<MCaptcha>; + + pub fn get_defense() -> Defense { + DefenseBuilder::default() + .add_level( + LevelBuilder::default() + .visitor_threshold(LEVEL_1.0) + .difficulty_factor(LEVEL_1.1) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .add_level( + LevelBuilder::default() + .visitor_threshold(LEVEL_2.0) + .difficulty_factor(LEVEL_2.1) + .unwrap() + .build() + .unwrap(), + ) + .unwrap() + .build() + .unwrap() + } + + async fn race(addr: Addr<MCaptcha>, count: (u32, u32)) { + for _ in 0..count.0 as usize - 1 { + let _ = addr.send(AddVisitor).await.unwrap(); + } + } + + pub fn get_counter() -> MCaptcha { + MCaptchaBuilder::default() + .defense(get_defense()) + .duration(DURATION) + .build() + .unwrap() + } + + #[actix_rt::test] + async fn counter_defense_tightenup_works() { + let addr: MyActor = get_counter().start(); + + let mut mcaptcha = addr.send(AddVisitor).await.unwrap(); + assert_eq!(mcaptcha.difficulty_factor, LEVEL_1.0); + + race(addr.clone(), LEVEL_2).await; + mcaptcha = addr.send(AddVisitor).await.unwrap(); + assert_eq!(mcaptcha.difficulty_factor, LEVEL_2.1); + } + + #[actix_rt::test] + async fn counter_defense_loosenup_works() { + //use actix::clock::sleep; + use actix::clock::delay_for; + let addr: MyActor = get_counter().start(); + + race(addr.clone(), LEVEL_2).await; + race(addr.clone(), LEVEL_2).await; + let mut mcaptcha = addr.send(AddVisitor).await.unwrap(); + assert_eq!(mcaptcha.difficulty_factor, LEVEL_2.1); + + let duration = Duration::new(DURATION, 0); + //sleep(duration).await; + delay_for(duration).await; + + mcaptcha = addr.send(AddVisitor).await.unwrap(); + assert_eq!(mcaptcha.difficulty_factor, LEVEL_1.1); + } + + #[test] + fn test_mcatcptha_builder() { + let defense = get_defense(); + let m = MCaptchaBuilder::default() + .duration(0) + .defense(defense.clone()) + .build(); + + assert_eq!(m.err(), Some(CaptchaError::CaptchaDurationZero)); + + let m = MCaptchaBuilder::default().duration(30).build(); + assert_eq!( + m.err(), + Some(CaptchaError::PleaseSetValue("defense".into())) + ); + + let m = MCaptchaBuilder::default().defense(defense.clone()).build(); + assert_eq!( + m.err(), + Some(CaptchaError::PleaseSetValue("duration".into())) + ); + } + + #[actix_rt::test] + async fn get_current_visitor_count_works() { + let addr: MyActor = get_counter().start(); + + addr.send(AddVisitor).await.unwrap(); + addr.send(AddVisitor).await.unwrap(); + addr.send(AddVisitor).await.unwrap(); + addr.send(AddVisitor).await.unwrap(); + let count = addr.send(GetCurrentVisitorCount).await.unwrap(); + + assert_eq!(count, 4); + } + + #[actix_rt::test] + #[should_panic] + async fn stop_works() { + let addr: MyActor = get_counter().start(); + addr.send(Stop).await.unwrap(); + addr.send(AddVisitor).await.unwrap(); + } +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +
+/* + * mCaptcha - A proof of work based DoS protection system + * Copyright © 2021 Aravinth Manivannan <realravinth@batsense.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +//! PoW datatypes used in client-server interaction +use pow_sha256::PoW; +use serde::{Deserialize, Serialize}; + +pub use pow_sha256::ConfigBuilder; + +/// PoW requirement datatype that is be sent to clients for generating PoW +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct PoWConfig { + pub string: String, + pub difficulty_factor: u32, +} +impl PoWConfig { + /// create new instance of [PoWConfig] + pub fn new(m: u32) -> Self { + use crate::utils::get_random; + + PoWConfig { + string: get_random(32), + difficulty_factor: m, + } + } +} + +/// PoW datatype that clients send to server +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct Work { + pub string: String, + pub result: String, + pub nonce: u64, + pub key: String, +} + +impl From<Work> for PoW<String> { + fn from(w: Work) -> Self { + use pow_sha256::PoWBuilder; + PoWBuilder::default() + .result(w.result) + .nonce(w.nonce) + .build() + .unwrap() + } +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +
+/* + * mCaptcha - A proof of work based DoS protection system + * Copyright © 2021 Aravinth Manivannan <realravinth@batsense.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +//! module describing mCaptcha system +use actix::dev::*; +use derive_builder::Builder; +use pow_sha256::Config; + +use crate::cache::messages::*; +use crate::cache::Save; +use crate::errors::*; +use crate::master::Master; +use crate::pow::*; + +/// struct describing various bits of data required for an mCaptcha system +#[derive(Clone, Builder)] +pub struct System<T: Save> { + pub master: Addr<Master>, + cache: Addr<T>, + pow: Config, +} + +impl<T> System<T> +where + T: Save, + <T as actix::Actor>::Context: ToEnvelope<T, CachePoW> + + ToEnvelope<T, RetrivePoW> + + ToEnvelope<T, CacheResult> + + ToEnvelope<T, VerifyCaptchaResult>, +{ + /// utility function to get difficulty factor of site `id` and cache it + pub async fn get_pow(&self, id: String) -> Option<PoWConfig> { + use crate::master::GetSite; + use crate::mcaptcha::AddVisitor; + + let site_addr = self.master.send(GetSite(id.clone())).await.unwrap(); + if site_addr.is_none() { + return None; + } + let mcaptcha = site_addr.unwrap().send(AddVisitor).await.unwrap(); + let pow_config = PoWConfig::new(mcaptcha.difficulty_factor); + + let cache_msg = CachePoWBuilder::default() + .string(pow_config.string.clone()) + .difficulty_factor(mcaptcha.difficulty_factor) + .duration(mcaptcha.duration) + .key(id) + .build() + .unwrap(); + + self.cache.send(cache_msg).await.unwrap().unwrap(); + Some(pow_config) + } + + /// utility function to verify [Work] + pub async fn verify_pow(&self, work: Work) -> CaptchaResult<String> { + let string = work.string.clone(); + let msg = RetrivePoW(string.clone()); + + let cached_config = self.cache.send(msg).await.unwrap()?; + + if cached_config.is_none() { + return Err(CaptchaError::StringNotFound); + } + + let cached_config = cached_config.unwrap(); + + if work.key != cached_config.key { + return Err(CaptchaError::MCaptchaKeyValidationFail); + } + + let pow = work.into(); + + if !self + .pow + .is_sufficient_difficulty(&pow, cached_config.difficulty_factor) + { + return Err(CaptchaError::InsuffiencientDifficulty); + } + + if !self.pow.is_valid_proof(&pow, &string) { + return Err(CaptchaError::InvalidPoW); + } + + let msg: CacheResult = cached_config.into(); + let res = msg.token.clone(); + self.cache.send(msg).await.unwrap()?; + Ok(res) + } + + /// utility function to validate verification tokens + pub async fn validate_verification_tokens( + &self, + msg: VerifyCaptchaResult, + ) -> CaptchaResult<bool> { + self.cache.send(msg).await.unwrap() + } +} + +#[cfg(test)] +mod tests { + + use pow_sha256::ConfigBuilder; + + use super::System; + use super::*; + use crate::cache::HashCache; + use crate::master::*; + use crate::mcaptcha::tests::*; + + const MCAPTCHA_NAME: &str = "batsense.net"; + + async fn boostrap_system(gc: u64) -> System<HashCache> { + let master = Master::new(gc).start(); + let mcaptcha = get_counter().start(); + let pow = get_config(); + + let cache = HashCache::default().start(); + let msg = AddSiteBuilder::default() + .id(MCAPTCHA_NAME.into()) + .addr(mcaptcha.clone()) + .build() + .unwrap(); + + master.send(msg).await.unwrap(); + + SystemBuilder::default() + .master(master) + .cache(cache) + .pow(pow) + .build() + .unwrap() + } + + fn get_config() -> Config { + ConfigBuilder::default() + .salt("myrandomsaltisnotlongenoug".into()) + .build() + .unwrap() + } + + #[actix_rt::test] + async fn get_pow_works() { + let actors = boostrap_system(10).await; + let pow = actors.get_pow(MCAPTCHA_NAME.into()).await.unwrap(); + assert_eq!(pow.difficulty_factor, LEVEL_1.0); + } + + #[actix_rt::test] + async fn verify_pow_works() { + // start system + let actors = boostrap_system(10).await; + // get work + let work_req = actors.get_pow(MCAPTCHA_NAME.into()).await.unwrap(); + // get config + let config = get_config(); + + // generate proof + let work = config + .prove_work(&work_req.string, work_req.difficulty_factor) + .unwrap(); + // generate proof payload + let mut payload = Work { + string: work_req.string, + result: work.result, + nonce: work.nonce, + key: MCAPTCHA_NAME.into(), + }; + + // verifiy proof + let res = actors.verify_pow(payload.clone()).await; + assert!(res.is_ok()); + + // verify validation token + let mut verifi_msg = VerifyCaptchaResult { + token: res.unwrap(), + key: MCAPTCHA_NAME.into(), + }; + assert!(actors + .validate_verification_tokens(verifi_msg.clone()) + .await + .unwrap()); + + // verify wrong validation token + verifi_msg.token = MCAPTCHA_NAME.into(); + assert!(!actors + .validate_verification_tokens(verifi_msg) + .await + .unwrap()); + + payload.string = "wrongstring".into(); + let res = actors.verify_pow(payload.clone()).await; + assert_eq!(res, Err(CaptchaError::StringNotFound)); + + let insufficient_work_req = actors.get_pow(MCAPTCHA_NAME.into()).await.unwrap(); + let insufficient_work = config.prove_work(&insufficient_work_req.string, 1).unwrap(); + let insufficient_work_payload = Work { + string: insufficient_work_req.string, + result: insufficient_work.result, + nonce: insufficient_work.nonce, + key: MCAPTCHA_NAME.into(), + }; + let res = actors.verify_pow(insufficient_work_payload.clone()).await; + assert_eq!(res, Err(CaptchaError::InsuffiencientDifficulty)); + + let sitekeyfail_config = actors.get_pow(MCAPTCHA_NAME.into()).await.unwrap(); + let sitekeyfail_work = config + .prove_work( + &sitekeyfail_config.string, + sitekeyfail_config.difficulty_factor, + ) + .unwrap(); + + let sitekeyfail = Work { + string: sitekeyfail_config.string, + result: sitekeyfail_work.result, + nonce: sitekeyfail_work.nonce, + key: "example.com".into(), + }; + + let res = actors.verify_pow(sitekeyfail).await; + assert_eq!(res, Err(CaptchaError::MCaptchaKeyValidationFail)); + } +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +
+/* + * mCaptcha - A proof of work based DoS protection system + * Copyright © 2021 Aravinth Manivannan <realravinth@batsense.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +// utility function to get a randomly generated string +// of size len +pub fn get_random(len: usize) -> String { + use std::iter; + + use rand::{distributions::Alphanumeric, rngs::ThreadRng, thread_rng, Rng}; + + let mut rng: ThreadRng = thread_rng(); + + iter::repeat(()) + .map(|()| rng.sample(Alphanumeric)) + .map(char::from) + .take(len) + .collect::<String>() +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Determine if a `char` is a valid identifier for a parser and/or lexer according to +//! [Unicode Standard Annex #31](http://www.unicode.org/reports/tr31/) rules. +//! +//! ```rust +//! extern crate unicode_xid; +//! +//! use unicode_xid::UnicodeXID; +//! +//! fn main() { +//! let ch = 'a'; +//! println!("Is {} a valid start of an identifier? {}", ch, UnicodeXID::is_xid_start(ch)); +//! } +//! ``` +//! +//! # features +//! +//! unicode-xid supports a `no_std` feature. This eliminates dependence +//! on std, and instead uses equivalent functions from core. +//! + +#![forbid(unsafe_code)] +#![deny(missing_docs)] +#![doc( + html_logo_url = "https://unicode-rs.github.io/unicode-rs_sm.png", + html_favicon_url = "https://unicode-rs.github.io/unicode-rs_sm.png" +)] +#![no_std] +#![cfg_attr(feature = "bench", feature(test, unicode_internals))] + +#[cfg(test)] +#[macro_use] +extern crate std; + +#[cfg(feature = "bench")] +extern crate test; + +use tables::derived_property; +pub use tables::UNICODE_VERSION; + +mod tables; + +#[cfg(test)] +mod tests; + +/// Methods for determining if a character is a valid identifier character. +pub trait UnicodeXID { + /// Returns whether the specified character satisfies the 'XID_Start' + /// Unicode property. + /// + /// 'XID_Start' is a Unicode Derived Property specified in + /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), + /// mostly similar to ID_Start but modified for closure under NFKx. + fn is_xid_start(self) -> bool; + + /// Returns whether the specified `char` satisfies the 'XID_Continue' + /// Unicode property. + /// + /// 'XID_Continue' is a Unicode Derived Property specified in + /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), + /// mostly similar to 'ID_Continue' but modified for closure under NFKx. + fn is_xid_continue(self) -> bool; +} + +impl UnicodeXID for char { + #[inline] + fn is_xid_start(self) -> bool { + derived_property::XID_Start(self) + } + + #[inline] + fn is_xid_continue(self) -> bool { + derived_property::XID_Continue(self) + } +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100 + 101 + 102 + 103 + 104 + 105 + 106 + 107 + 108 + 109 + 110 + 111 + 112 + 113 + 114 + 115 + 116 + 117 + 118 + 119 + 120 + 121 + 122 + 123 + 124 + 125 + 126 + 127 + 128 + 129 + 130 + 131 + 132 + 133 + 134 + 135 + 136 + 137 + 138 + 139 + 140 + 141 + 142 + 143 + 144 + 145 + 146 + 147 + 148 + 149 + 150 + 151 + 152 + 153 + 154 + 155 + 156 + 157 + 158 + 159 + 160 + 161 + 162 + 163 + 164 + 165 + 166 + 167 + 168 + 169 + 170 + 171 + 172 + 173 + 174 + 175 + 176 + 177 + 178 + 179 + 180 + 181 + 182 + 183 + 184 + 185 + 186 + 187 + 188 + 189 + 190 + 191 + 192 + 193 + 194 + 195 + 196 + 197 + 198 + 199 + 200 + 201 + 202 + 203 + 204 + 205 + 206 + 207 + 208 + 209 + 210 + 211 + 212 + 213 + 214 + 215 + 216 + 217 + 218 + 219 + 220 + 221 + 222 + 223 + 224 + 225 + 226 + 227 + 228 + 229 + 230 + 231 + 232 + 233 + 234 + 235 + 236 + 237 + 238 + 239 + 240 + 241 + 242 + 243 + 244 + 245 + 246 + 247 + 248 + 249 + 250 + 251 + 252 + 253 + 254 + 255 + 256 + 257 + 258 + 259 + 260 + 261 + 262 + 263 + 264 + 265 + 266 + 267 + 268 + 269 + 270 + 271 + 272 + 273 + 274 + 275 + 276 + 277 + 278 + 279 + 280 + 281 + 282 + 283 + 284 + 285 + 286 + 287 + 288 + 289 + 290 + 291 + 292 + 293 + 294 + 295 + 296 + 297 + 298 + 299 + 300 + 301 + 302 + 303 + 304 + 305 + 306 + 307 + 308 + 309 + 310 + 311 + 312 + 313 + 314 + 315 + 316 + 317 + 318 + 319 + 320 + 321 + 322 + 323 + 324 + 325 + 326 + 327 + 328 + 329 + 330 + 331 + 332 + 333 + 334 + 335 + 336 + 337 + 338 + 339 + 340 + 341 + 342 + 343 + 344 + 345 + 346 + 347 + 348 + 349 + 350 + 351 + 352 + 353 + 354 + 355 + 356 + 357 + 358 + 359 + 360 + 361 + 362 + 363 + 364 + 365 + 366 + 367 + 368 + 369 + 370 + 371 + 372 + 373 + 374 + 375 + 376 + 377 + 378 + 379 + 380 + 381 + 382 + 383 + 384 + 385 + 386 + 387 + 388 + 389 + 390 + 391 + 392 + 393 + 394 + 395 + 396 + 397 + 398 + 399 + 400 + 401 + 402 + 403 + 404 + 405 + 406 + 407 + 408 + 409 + 410 + 411 + 412 + 413 + 414 + 415 + 416 + 417 + 418 + 419 + 420 + 421 + 422 + 423 + 424 + 425 + 426 + 427 + 428 + 429 + 430 + 431 + 432 + 433 + 434 + 435 + 436 + 437 + 438 + 439 + 440 + 441 + 442 + 443 + 444 + 445 + 446 + 447 + 448 + 449 + 450 + 451 + 452 + 453 + 454 + 455 + 456 + 457 + 458 + 459 + 460 + 461 + 462 + 463 + 464 + 465 + 466 + 467 + 468 + 469 + 470 + 471 + 472 + 473 + 474 + 475 + 476 + 477 + 478 + 479 + 480 + 481 + 482 + 483 + 484 + 485 + 486 + 487 + 488 + 489 + 490 + 491 + 492 + 493 + 494 + 495 + 496 + 497 + 498 + 499 + 500 + 501 + 502 + 503 + 504 + 505 + 506 + 507 + 508 + 509 + 510 + 511 + 512 + 513 + 514 + 515 + 516 + 517 + 518 + 519 + 520 + 521 + 522 + 523 + 524 + 525 + 526 + 527 + 528 + 529 + 530 + 531 + 532 + 533 + 534 + 535 + 536 + 537 + 538 + 539 + 540 + 541 + 542 + 543 + 544 + 545 + 546 + 547 + 548 + 549 + 550 + 551 + 552 + 553 + 554 + 555 + 556 + 557 + 558 + 559 + 560 + 561 + 562 + 563 + 564 + 565 + 566 + 567 + 568 + 569 + 570 + 571 + 572 + 573 + 574 + 575 + 576 + 577 + 578 + 579 + 580 + 581 + 582 + 583 + 584 + 585 + 586 + 587 + 588 + 589 + 590 + 591 + 592 + 593 + 594 + 595 + 596 + 597 + 598 + 599 + 600 + 601 + 602 + 603 + 604 + 605 + 606 + 607 + 608 + 609 + 610 + 611 + 612 + 613 + 614 + 615 + 616 + 617 + 618 + 619 + 620 + 621 + 622 + 623 + 624 + 625 + 626 + 627 + 628 + 629 + 630 + 631 + 632 + 633 + 634 + 635 + 636 + 637 + 638 + 639 + 640 + 641 + 642 + 643 + 644 + 645 + 646 + 647 + 648 + 649 + 650 + 651 + 652 + 653 + 654 + 655 + 656 + 657 + 658 + 659 + 660 + 661 + 662 + 663 + 664 + 665 + 666 + 667 + 668 + 669 + 670 + 671 + 672 + 673 + 674 + 675 + 676 + 677 + 678 + 679 + 680 + 681 + 682 + 683 + 684 + 685 + 686 + 687 + 688 + 689 + 690 + 691 + 692 + 693 + 694 + 695 + 696 + 697 + 698 + 699 + 700 + 701 + 702 + 703 + 704 + 705 + 706 + 707 + 708 + 709 + 710 + 711 + 712 + 713 + 714 + 715 + 716 + 717 + 718 + 719 + 720 + 721 + 722 + 723 + 724 + 725 + 726 + 727 + 728 + 729 + 730 + 731 + 732 + 733 + 734 + 735 + 736 + 737 + 738 + 739 + 740 + 741 + 742 + 743 + 744 + 745 + 746 + 747 + 748 + 749 + 750 + 751 + 752 + 753 + 754 + 755 + 756 + 757 + 758 + 759 + 760 + 761 + 762 + 763 + 764 + 765 + 766 + 767 + 768 + 769 + 770 + 771 + 772 + 773 + 774 + 775 + 776 + 777 + 778 + 779 + 780 + 781 + 782 + 783 + 784 + 785 + 786 + 787 + 788 + 789 + 790 + 791 + 792 + 793 + 794 + 795 + 796 + 797 + 798 + 799 + 800 + 801 + 802 + 803 + 804 + 805 + 806 + 807 + 808 + 809 + 810 + 811 + 812 + 813 + 814 + 815 + 816 + 817 + 818 + 819 + 820 + 821 + 822 + 823 + 824 + 825 + 826 + 827 + 828 + 829 + 830 + 831 + 832 + 833 + 834 + 835 + 836 + 837 + 838 + 839 + 840 + 841 + 842 + 843 + 844 + 845 + 846 + 847 + 848 + 849 + 850 + 851 + 852 + 853 + 854 + 855 + 856 + 857 + 858 + 859 + 860 + 861 + 862 + 863 + 864 + 865 + 866 + 867 + 868 + 869 + 870 + 871 + 872 + 873 + 874 + 875 + 876 + 877 + 878 + 879 + 880 + 881 + 882 + 883 + 884 + 885 + 886 + 887 + 888 + 889 + 890 + 891 + 892 + 893 + 894 + 895 + 896 + 897 + 898 + 899 + 900 + 901 + 902 + 903 + 904 + 905 + 906 + 907 + 908 + 909 + 910 + 911 + 912 + 913 + 914 + 915 + 916 + 917 + 918 + 919 + 920 + 921 + 922 + 923 + 924 + 925 + 926 + 927 + 928 + 929 + 930 + 931 + 932 + 933 + 934 + 935 + 936 + 937 + 938 + 939 + 940 + 941 + 942 + 943 + 944 + 945 + 946 + 947 + 948 + 949 + 950 + 951 + 952 + 953 + 954 + 955 + 956 + 957 + 958 + 959 + 960 + 961 + 962 + 963 + 964 + 965 + 966 + 967 + 968 + 969 + 970 + 971 + 972 + 973 + 974 + 975 + 976 + 977 + 978 + 979 + 980 + 981 + 982 + 983 + 984 + 985 + 986 + 987 + 988 + 989 + 990 + 991 + 992 + 993 + 994 + 995 + 996 + 997 + 998 + 999 +1000 +1001 +1002 +1003 +1004 +1005 +1006 +1007 +1008 +1009 +1010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +1030 +1031 +1032 +1033 +1034 +1035 +1036 +1037 +1038 +1039 +1040 +1041 +1042 +1043 +1044 +1045 +1046 +1047 +1048 +1049 +1050 +1051 +1052 +1053 +1054 +1055 +1056 +1057 +1058 +1059 +1060 +1061 +1062 +1063 +1064 +1065 +1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +1193 +1194 +1195 +1196 +1197 +1198 +1199 +1200 +1201 +1202 +1203 +1204 +1205 +1206 +1207 +1208 +1209 +1210 +1211 +1212 +1213 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229 +1230 +1231 +1232 +1233 +1234 +1235 +1236 +1237 +1238 +1239 +1240 +1241 +1242 +1243 +1244 +1245 +1246 +1247 +1248 +1249 +1250 +1251 +1252 +1253 +1254 +1255 +1256 +1257 +1258 +1259 +1260 +1261 +1262 +1263 +1264 +1265 +1266 +1267 +1268 +1269 +1270 +1271 +1272 +1273 +1274 +1275 +1276 +1277 +1278 +1279 +1280 +1281 +1282 +1283 +1284 +1285 +1286 +1287 +1288 +1289 +1290 +1291 +1292 +1293 +1294 +1295 +1296 +1297 +1298 +1299 +1300 +1301 +1302 +1303 +1304 +1305 +1306 +1307 +1308 +1309 +1310 +1311 +1312 +1313 +1314 +1315 +1316 +1317 +1318 +1319 +1320 +1321 +1322 +1323 +1324 +1325 +1326 +1327 +1328 +1329 +1330 +1331 +1332 +1333 +1334 +1335 +1336 +1337 +1338 +1339 +1340 +1341 +1342 +1343 +1344 +1345 +1346 +1347 +1348 +1349 +1350 +1351 +1352 +1353 +1354 +1355 +1356 +1357 +1358 +1359 +1360 +1361 +1362 +1363 +1364 +1365 +1366 +1367 +1368 +1369 +1370 +1371 +1372 +1373 +1374 +1375 +1376 +1377 +1378 +1379 +1380 +1381 +1382 +1383 +1384 +1385 +1386 +1387 +1388 +1389 +1390 +1391 +1392 +1393 +1394 +1395 +1396 +1397 +1398 +1399 +1400 +1401 +1402 +1403 +1404 +1405 +1406 +1407 +1408 +1409 +1410 +1411 +1412 +1413 +1414 +1415 +1416 +1417 +1418 +1419 +
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly + +#![allow(missing_docs, non_upper_case_globals, non_snake_case)] + +/// The version of [Unicode](http://www.unicode.org/) +/// that this version of unicode-xid is based on. +pub const UNICODE_VERSION: (u64, u64, u64) = (13, 0, 0); + +fn bsearch_range_table(c: char, r: &[(char, char)]) -> bool { + use core::cmp::Ordering::{Equal, Greater, Less}; + + r.binary_search_by(|&(lo, hi)| { + // Because ASCII ranges are at the start of the tables, a search for an + // ASCII char will involve more `Greater` results (i.e. the `(lo,hi)` + // table entry is greater than `c`) than `Less` results. And given that + // ASCII chars are so common, it makes sense to favor them. Therefore, + // the `Greater` case is tested for before the `Less` case. + if lo > c { + Greater + } else if hi < c { + Less + } else { + Equal + } + }) + .is_ok() +} + +pub mod derived_property { + pub const XID_Continue_table: &[(char, char)] = &[ + ('\u{30}', '\u{39}'), + ('\u{41}', '\u{5a}'), + ('\u{5f}', '\u{5f}'), + ('\u{61}', '\u{7a}'), + ('\u{aa}', '\u{aa}'), + ('\u{b5}', '\u{b5}'), + ('\u{b7}', '\u{b7}'), + ('\u{ba}', '\u{ba}'), + ('\u{c0}', '\u{d6}'), + ('\u{d8}', '\u{f6}'), + ('\u{f8}', '\u{2c1}'), + ('\u{2c6}', '\u{2d1}'), + ('\u{2e0}', '\u{2e4}'), + ('\u{2ec}', '\u{2ec}'), + ('\u{2ee}', '\u{2ee}'), + ('\u{300}', '\u{374}'), + ('\u{376}', '\u{377}'), + ('\u{37b}', '\u{37d}'), + ('\u{37f}', '\u{37f}'), + ('\u{386}', '\u{38a}'), + ('\u{38c}', '\u{38c}'), + ('\u{38e}', '\u{3a1}'), + ('\u{3a3}', '\u{3f5}'), + ('\u{3f7}', '\u{481}'), + ('\u{483}', '\u{487}'), + ('\u{48a}', '\u{52f}'), + ('\u{531}', '\u{556}'), + ('\u{559}', '\u{559}'), + ('\u{560}', '\u{588}'), + ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('\u{5d0}', '\u{5ea}'), + ('\u{5ef}', '\u{5f2}'), + ('\u{610}', '\u{61a}'), + ('\u{620}', '\u{669}'), + ('\u{66e}', '\u{6d3}'), + ('\u{6d5}', '\u{6dc}'), + ('\u{6df}', '\u{6e8}'), + ('\u{6ea}', '\u{6fc}'), + ('\u{6ff}', '\u{6ff}'), + ('\u{710}', '\u{74a}'), + ('\u{74d}', '\u{7b1}'), + ('\u{7c0}', '\u{7f5}'), + ('\u{7fa}', '\u{7fa}'), + ('\u{7fd}', '\u{7fd}'), + ('\u{800}', '\u{82d}'), + ('\u{840}', '\u{85b}'), + ('\u{860}', '\u{86a}'), + ('\u{8a0}', '\u{8b4}'), + ('\u{8b6}', '\u{8c7}'), + ('\u{8d3}', '\u{8e1}'), + ('\u{8e3}', '\u{963}'), + ('\u{966}', '\u{96f}'), + ('\u{971}', '\u{983}'), + ('\u{985}', '\u{98c}'), + ('\u{98f}', '\u{990}'), + ('\u{993}', '\u{9a8}'), + ('\u{9aa}', '\u{9b0}'), + ('\u{9b2}', '\u{9b2}'), + ('\u{9b6}', '\u{9b9}'), + ('\u{9bc}', '\u{9c4}'), + ('\u{9c7}', '\u{9c8}'), + ('\u{9cb}', '\u{9ce}'), + ('\u{9d7}', '\u{9d7}'), + ('\u{9dc}', '\u{9dd}'), + ('\u{9df}', '\u{9e3}'), + ('\u{9e6}', '\u{9f1}'), + ('\u{9fc}', '\u{9fc}'), + ('\u{9fe}', '\u{9fe}'), + ('\u{a01}', '\u{a03}'), + ('\u{a05}', '\u{a0a}'), + ('\u{a0f}', '\u{a10}'), + ('\u{a13}', '\u{a28}'), + ('\u{a2a}', '\u{a30}'), + ('\u{a32}', '\u{a33}'), + ('\u{a35}', '\u{a36}'), + ('\u{a38}', '\u{a39}'), + ('\u{a3c}', '\u{a3c}'), + ('\u{a3e}', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('\u{a59}', '\u{a5c}'), + ('\u{a5e}', '\u{a5e}'), + ('\u{a66}', '\u{a75}'), + ('\u{a81}', '\u{a83}'), + ('\u{a85}', '\u{a8d}'), + ('\u{a8f}', '\u{a91}'), + ('\u{a93}', '\u{aa8}'), + ('\u{aaa}', '\u{ab0}'), + ('\u{ab2}', '\u{ab3}'), + ('\u{ab5}', '\u{ab9}'), + ('\u{abc}', '\u{ac5}'), + ('\u{ac7}', '\u{ac9}'), + ('\u{acb}', '\u{acd}'), + ('\u{ad0}', '\u{ad0}'), + ('\u{ae0}', '\u{ae3}'), + ('\u{ae6}', '\u{aef}'), + ('\u{af9}', '\u{aff}'), + ('\u{b01}', '\u{b03}'), + ('\u{b05}', '\u{b0c}'), + ('\u{b0f}', '\u{b10}'), + ('\u{b13}', '\u{b28}'), + ('\u{b2a}', '\u{b30}'), + ('\u{b32}', '\u{b33}'), + ('\u{b35}', '\u{b39}'), + ('\u{b3c}', '\u{b44}'), + ('\u{b47}', '\u{b48}'), + ('\u{b4b}', '\u{b4d}'), + ('\u{b55}', '\u{b57}'), + ('\u{b5c}', '\u{b5d}'), + ('\u{b5f}', '\u{b63}'), + ('\u{b66}', '\u{b6f}'), + ('\u{b71}', '\u{b71}'), + ('\u{b82}', '\u{b83}'), + ('\u{b85}', '\u{b8a}'), + ('\u{b8e}', '\u{b90}'), + ('\u{b92}', '\u{b95}'), + ('\u{b99}', '\u{b9a}'), + ('\u{b9c}', '\u{b9c}'), + ('\u{b9e}', '\u{b9f}'), + ('\u{ba3}', '\u{ba4}'), + ('\u{ba8}', '\u{baa}'), + ('\u{bae}', '\u{bb9}'), + ('\u{bbe}', '\u{bc2}'), + ('\u{bc6}', '\u{bc8}'), + ('\u{bca}', '\u{bcd}'), + ('\u{bd0}', '\u{bd0}'), + ('\u{bd7}', '\u{bd7}'), + ('\u{be6}', '\u{bef}'), + ('\u{c00}', '\u{c0c}'), + ('\u{c0e}', '\u{c10}'), + ('\u{c12}', '\u{c28}'), + ('\u{c2a}', '\u{c39}'), + ('\u{c3d}', '\u{c44}'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('\u{c58}', '\u{c5a}'), + ('\u{c60}', '\u{c63}'), + ('\u{c66}', '\u{c6f}'), + ('\u{c80}', '\u{c83}'), + ('\u{c85}', '\u{c8c}'), + ('\u{c8e}', '\u{c90}'), + ('\u{c92}', '\u{ca8}'), + ('\u{caa}', '\u{cb3}'), + ('\u{cb5}', '\u{cb9}'), + ('\u{cbc}', '\u{cc4}'), + ('\u{cc6}', '\u{cc8}'), + ('\u{cca}', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), + ('\u{cde}', '\u{cde}'), + ('\u{ce0}', '\u{ce3}'), + ('\u{ce6}', '\u{cef}'), + ('\u{cf1}', '\u{cf2}'), + ('\u{d00}', '\u{d0c}'), + ('\u{d0e}', '\u{d10}'), + ('\u{d12}', '\u{d44}'), + ('\u{d46}', '\u{d48}'), + ('\u{d4a}', '\u{d4e}'), + ('\u{d54}', '\u{d57}'), + ('\u{d5f}', '\u{d63}'), + ('\u{d66}', '\u{d6f}'), + ('\u{d7a}', '\u{d7f}'), + ('\u{d81}', '\u{d83}'), + ('\u{d85}', '\u{d96}'), + ('\u{d9a}', '\u{db1}'), + ('\u{db3}', '\u{dbb}'), + ('\u{dbd}', '\u{dbd}'), + ('\u{dc0}', '\u{dc6}'), + ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('\u{dd8}', '\u{ddf}'), + ('\u{de6}', '\u{def}'), + ('\u{df2}', '\u{df3}'), + ('\u{e01}', '\u{e3a}'), + ('\u{e40}', '\u{e4e}'), + ('\u{e50}', '\u{e59}'), + ('\u{e81}', '\u{e82}'), + ('\u{e84}', '\u{e84}'), + ('\u{e86}', '\u{e8a}'), + ('\u{e8c}', '\u{ea3}'), + ('\u{ea5}', '\u{ea5}'), + ('\u{ea7}', '\u{ebd}'), + ('\u{ec0}', '\u{ec4}'), + ('\u{ec6}', '\u{ec6}'), + ('\u{ec8}', '\u{ecd}'), + ('\u{ed0}', '\u{ed9}'), + ('\u{edc}', '\u{edf}'), + ('\u{f00}', '\u{f00}'), + ('\u{f18}', '\u{f19}'), + ('\u{f20}', '\u{f29}'), + ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), + ('\u{f39}', '\u{f39}'), + ('\u{f3e}', '\u{f47}'), + ('\u{f49}', '\u{f6c}'), + ('\u{f71}', '\u{f84}'), + ('\u{f86}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('\u{fc6}', '\u{fc6}'), + ('\u{1000}', '\u{1049}'), + ('\u{1050}', '\u{109d}'), + ('\u{10a0}', '\u{10c5}'), + ('\u{10c7}', '\u{10c7}'), + ('\u{10cd}', '\u{10cd}'), + ('\u{10d0}', '\u{10fa}'), + ('\u{10fc}', '\u{1248}'), + ('\u{124a}', '\u{124d}'), + ('\u{1250}', '\u{1256}'), + ('\u{1258}', '\u{1258}'), + ('\u{125a}', '\u{125d}'), + ('\u{1260}', '\u{1288}'), + ('\u{128a}', '\u{128d}'), + ('\u{1290}', '\u{12b0}'), + ('\u{12b2}', '\u{12b5}'), + ('\u{12b8}', '\u{12be}'), + ('\u{12c0}', '\u{12c0}'), + ('\u{12c2}', '\u{12c5}'), + ('\u{12c8}', '\u{12d6}'), + ('\u{12d8}', '\u{1310}'), + ('\u{1312}', '\u{1315}'), + ('\u{1318}', '\u{135a}'), + ('\u{135d}', '\u{135f}'), + ('\u{1369}', '\u{1371}'), + ('\u{1380}', '\u{138f}'), + ('\u{13a0}', '\u{13f5}'), + ('\u{13f8}', '\u{13fd}'), + ('\u{1401}', '\u{166c}'), + ('\u{166f}', '\u{167f}'), + ('\u{1681}', '\u{169a}'), + ('\u{16a0}', '\u{16ea}'), + ('\u{16ee}', '\u{16f8}'), + ('\u{1700}', '\u{170c}'), + ('\u{170e}', '\u{1714}'), + ('\u{1720}', '\u{1734}'), + ('\u{1740}', '\u{1753}'), + ('\u{1760}', '\u{176c}'), + ('\u{176e}', '\u{1770}'), + ('\u{1772}', '\u{1773}'), + ('\u{1780}', '\u{17d3}'), + ('\u{17d7}', '\u{17d7}'), + ('\u{17dc}', '\u{17dd}'), + ('\u{17e0}', '\u{17e9}'), + ('\u{180b}', '\u{180d}'), + ('\u{1810}', '\u{1819}'), + ('\u{1820}', '\u{1878}'), + ('\u{1880}', '\u{18aa}'), + ('\u{18b0}', '\u{18f5}'), + ('\u{1900}', '\u{191e}'), + ('\u{1920}', '\u{192b}'), + ('\u{1930}', '\u{193b}'), + ('\u{1946}', '\u{196d}'), + ('\u{1970}', '\u{1974}'), + ('\u{1980}', '\u{19ab}'), + ('\u{19b0}', '\u{19c9}'), + ('\u{19d0}', '\u{19da}'), + ('\u{1a00}', '\u{1a1b}'), + ('\u{1a20}', '\u{1a5e}'), + ('\u{1a60}', '\u{1a7c}'), + ('\u{1a7f}', '\u{1a89}'), + ('\u{1a90}', '\u{1a99}'), + ('\u{1aa7}', '\u{1aa7}'), + ('\u{1ab0}', '\u{1abd}'), + ('\u{1abf}', '\u{1ac0}'), + ('\u{1b00}', '\u{1b4b}'), + ('\u{1b50}', '\u{1b59}'), + ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', '\u{1bf3}'), + ('\u{1c00}', '\u{1c37}'), + ('\u{1c40}', '\u{1c49}'), + ('\u{1c4d}', '\u{1c7d}'), + ('\u{1c80}', '\u{1c88}'), + ('\u{1c90}', '\u{1cba}'), + ('\u{1cbd}', '\u{1cbf}'), + ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', '\u{1cfa}'), + ('\u{1d00}', '\u{1df9}'), + ('\u{1dfb}', '\u{1f15}'), + ('\u{1f18}', '\u{1f1d}'), + ('\u{1f20}', '\u{1f45}'), + ('\u{1f48}', '\u{1f4d}'), + ('\u{1f50}', '\u{1f57}'), + ('\u{1f59}', '\u{1f59}'), + ('\u{1f5b}', '\u{1f5b}'), + ('\u{1f5d}', '\u{1f5d}'), + ('\u{1f5f}', '\u{1f7d}'), + ('\u{1f80}', '\u{1fb4}'), + ('\u{1fb6}', '\u{1fbc}'), + ('\u{1fbe}', '\u{1fbe}'), + ('\u{1fc2}', '\u{1fc4}'), + ('\u{1fc6}', '\u{1fcc}'), + ('\u{1fd0}', '\u{1fd3}'), + ('\u{1fd6}', '\u{1fdb}'), + ('\u{1fe0}', '\u{1fec}'), + ('\u{1ff2}', '\u{1ff4}'), + ('\u{1ff6}', '\u{1ffc}'), + ('\u{203f}', '\u{2040}'), + ('\u{2054}', '\u{2054}'), + ('\u{2071}', '\u{2071}'), + ('\u{207f}', '\u{207f}'), + ('\u{2090}', '\u{209c}'), + ('\u{20d0}', '\u{20dc}'), + ('\u{20e1}', '\u{20e1}'), + ('\u{20e5}', '\u{20f0}'), + ('\u{2102}', '\u{2102}'), + ('\u{2107}', '\u{2107}'), + ('\u{210a}', '\u{2113}'), + ('\u{2115}', '\u{2115}'), + ('\u{2118}', '\u{211d}'), + ('\u{2124}', '\u{2124}'), + ('\u{2126}', '\u{2126}'), + ('\u{2128}', '\u{2128}'), + ('\u{212a}', '\u{2139}'), + ('\u{213c}', '\u{213f}'), + ('\u{2145}', '\u{2149}'), + ('\u{214e}', '\u{214e}'), + ('\u{2160}', '\u{2188}'), + ('\u{2c00}', '\u{2c2e}'), + ('\u{2c30}', '\u{2c5e}'), + ('\u{2c60}', '\u{2ce4}'), + ('\u{2ceb}', '\u{2cf3}'), + ('\u{2d00}', '\u{2d25}'), + ('\u{2d27}', '\u{2d27}'), + ('\u{2d2d}', '\u{2d2d}'), + ('\u{2d30}', '\u{2d67}'), + ('\u{2d6f}', '\u{2d6f}'), + ('\u{2d7f}', '\u{2d96}'), + ('\u{2da0}', '\u{2da6}'), + ('\u{2da8}', '\u{2dae}'), + ('\u{2db0}', '\u{2db6}'), + ('\u{2db8}', '\u{2dbe}'), + ('\u{2dc0}', '\u{2dc6}'), + ('\u{2dc8}', '\u{2dce}'), + ('\u{2dd0}', '\u{2dd6}'), + ('\u{2dd8}', '\u{2dde}'), + ('\u{2de0}', '\u{2dff}'), + ('\u{3005}', '\u{3007}'), + ('\u{3021}', '\u{302f}'), + ('\u{3031}', '\u{3035}'), + ('\u{3038}', '\u{303c}'), + ('\u{3041}', '\u{3096}'), + ('\u{3099}', '\u{309a}'), + ('\u{309d}', '\u{309f}'), + ('\u{30a1}', '\u{30fa}'), + ('\u{30fc}', '\u{30ff}'), + ('\u{3105}', '\u{312f}'), + ('\u{3131}', '\u{318e}'), + ('\u{31a0}', '\u{31bf}'), + ('\u{31f0}', '\u{31ff}'), + ('\u{3400}', '\u{4dbf}'), + ('\u{4e00}', '\u{9ffc}'), + ('\u{a000}', '\u{a48c}'), + ('\u{a4d0}', '\u{a4fd}'), + ('\u{a500}', '\u{a60c}'), + ('\u{a610}', '\u{a62b}'), + ('\u{a640}', '\u{a66f}'), + ('\u{a674}', '\u{a67d}'), + ('\u{a67f}', '\u{a6f1}'), + ('\u{a717}', '\u{a71f}'), + ('\u{a722}', '\u{a788}'), + ('\u{a78b}', '\u{a7bf}'), + ('\u{a7c2}', '\u{a7ca}'), + ('\u{a7f5}', '\u{a827}'), + ('\u{a82c}', '\u{a82c}'), + ('\u{a840}', '\u{a873}'), + ('\u{a880}', '\u{a8c5}'), + ('\u{a8d0}', '\u{a8d9}'), + ('\u{a8e0}', '\u{a8f7}'), + ('\u{a8fb}', '\u{a8fb}'), + ('\u{a8fd}', '\u{a92d}'), + ('\u{a930}', '\u{a953}'), + ('\u{a960}', '\u{a97c}'), + ('\u{a980}', '\u{a9c0}'), + ('\u{a9cf}', '\u{a9d9}'), + ('\u{a9e0}', '\u{a9fe}'), + ('\u{aa00}', '\u{aa36}'), + ('\u{aa40}', '\u{aa4d}'), + ('\u{aa50}', '\u{aa59}'), + ('\u{aa60}', '\u{aa76}'), + ('\u{aa7a}', '\u{aac2}'), + ('\u{aadb}', '\u{aadd}'), + ('\u{aae0}', '\u{aaef}'), + ('\u{aaf2}', '\u{aaf6}'), + ('\u{ab01}', '\u{ab06}'), + ('\u{ab09}', '\u{ab0e}'), + ('\u{ab11}', '\u{ab16}'), + ('\u{ab20}', '\u{ab26}'), + ('\u{ab28}', '\u{ab2e}'), + ('\u{ab30}', '\u{ab5a}'), + ('\u{ab5c}', '\u{ab69}'), + ('\u{ab70}', '\u{abea}'), + ('\u{abec}', '\u{abed}'), + ('\u{abf0}', '\u{abf9}'), + ('\u{ac00}', '\u{d7a3}'), + ('\u{d7b0}', '\u{d7c6}'), + ('\u{d7cb}', '\u{d7fb}'), + ('\u{f900}', '\u{fa6d}'), + ('\u{fa70}', '\u{fad9}'), + ('\u{fb00}', '\u{fb06}'), + ('\u{fb13}', '\u{fb17}'), + ('\u{fb1d}', '\u{fb28}'), + ('\u{fb2a}', '\u{fb36}'), + ('\u{fb38}', '\u{fb3c}'), + ('\u{fb3e}', '\u{fb3e}'), + ('\u{fb40}', '\u{fb41}'), + ('\u{fb43}', '\u{fb44}'), + ('\u{fb46}', '\u{fbb1}'), + ('\u{fbd3}', '\u{fc5d}'), + ('\u{fc64}', '\u{fd3d}'), + ('\u{fd50}', '\u{fd8f}'), + ('\u{fd92}', '\u{fdc7}'), + ('\u{fdf0}', '\u{fdf9}'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2f}'), + ('\u{fe33}', '\u{fe34}'), + ('\u{fe4d}', '\u{fe4f}'), + ('\u{fe71}', '\u{fe71}'), + ('\u{fe73}', '\u{fe73}'), + ('\u{fe77}', '\u{fe77}'), + ('\u{fe79}', '\u{fe79}'), + ('\u{fe7b}', '\u{fe7b}'), + ('\u{fe7d}', '\u{fe7d}'), + ('\u{fe7f}', '\u{fefc}'), + ('\u{ff10}', '\u{ff19}'), + ('\u{ff21}', '\u{ff3a}'), + ('\u{ff3f}', '\u{ff3f}'), + ('\u{ff41}', '\u{ff5a}'), + ('\u{ff66}', '\u{ffbe}'), + ('\u{ffc2}', '\u{ffc7}'), + ('\u{ffca}', '\u{ffcf}'), + ('\u{ffd2}', '\u{ffd7}'), + ('\u{ffda}', '\u{ffdc}'), + ('\u{10000}', '\u{1000b}'), + ('\u{1000d}', '\u{10026}'), + ('\u{10028}', '\u{1003a}'), + ('\u{1003c}', '\u{1003d}'), + ('\u{1003f}', '\u{1004d}'), + ('\u{10050}', '\u{1005d}'), + ('\u{10080}', '\u{100fa}'), + ('\u{10140}', '\u{10174}'), + ('\u{101fd}', '\u{101fd}'), + ('\u{10280}', '\u{1029c}'), + ('\u{102a0}', '\u{102d0}'), + ('\u{102e0}', '\u{102e0}'), + ('\u{10300}', '\u{1031f}'), + ('\u{1032d}', '\u{1034a}'), + ('\u{10350}', '\u{1037a}'), + ('\u{10380}', '\u{1039d}'), + ('\u{103a0}', '\u{103c3}'), + ('\u{103c8}', '\u{103cf}'), + ('\u{103d1}', '\u{103d5}'), + ('\u{10400}', '\u{1049d}'), + ('\u{104a0}', '\u{104a9}'), + ('\u{104b0}', '\u{104d3}'), + ('\u{104d8}', '\u{104fb}'), + ('\u{10500}', '\u{10527}'), + ('\u{10530}', '\u{10563}'), + ('\u{10600}', '\u{10736}'), + ('\u{10740}', '\u{10755}'), + ('\u{10760}', '\u{10767}'), + ('\u{10800}', '\u{10805}'), + ('\u{10808}', '\u{10808}'), + ('\u{1080a}', '\u{10835}'), + ('\u{10837}', '\u{10838}'), + ('\u{1083c}', '\u{1083c}'), + ('\u{1083f}', '\u{10855}'), + ('\u{10860}', '\u{10876}'), + ('\u{10880}', '\u{1089e}'), + ('\u{108e0}', '\u{108f2}'), + ('\u{108f4}', '\u{108f5}'), + ('\u{10900}', '\u{10915}'), + ('\u{10920}', '\u{10939}'), + ('\u{10980}', '\u{109b7}'), + ('\u{109be}', '\u{109bf}'), + ('\u{10a00}', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a13}'), + ('\u{10a15}', '\u{10a17}'), + ('\u{10a19}', '\u{10a35}'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), + ('\u{10a60}', '\u{10a7c}'), + ('\u{10a80}', '\u{10a9c}'), + ('\u{10ac0}', '\u{10ac7}'), + ('\u{10ac9}', '\u{10ae6}'), + ('\u{10b00}', '\u{10b35}'), + ('\u{10b40}', '\u{10b55}'), + ('\u{10b60}', '\u{10b72}'), + ('\u{10b80}', '\u{10b91}'), + ('\u{10c00}', '\u{10c48}'), + ('\u{10c80}', '\u{10cb2}'), + ('\u{10cc0}', '\u{10cf2}'), + ('\u{10d00}', '\u{10d27}'), + ('\u{10d30}', '\u{10d39}'), + ('\u{10e80}', '\u{10ea9}'), + ('\u{10eab}', '\u{10eac}'), + ('\u{10eb0}', '\u{10eb1}'), + ('\u{10f00}', '\u{10f1c}'), + ('\u{10f27}', '\u{10f27}'), + ('\u{10f30}', '\u{10f50}'), + ('\u{10fb0}', '\u{10fc4}'), + ('\u{10fe0}', '\u{10ff6}'), + ('\u{11000}', '\u{11046}'), + ('\u{11066}', '\u{1106f}'), + ('\u{1107f}', '\u{110ba}'), + ('\u{110d0}', '\u{110e8}'), + ('\u{110f0}', '\u{110f9}'), + ('\u{11100}', '\u{11134}'), + ('\u{11136}', '\u{1113f}'), + ('\u{11144}', '\u{11147}'), + ('\u{11150}', '\u{11173}'), + ('\u{11176}', '\u{11176}'), + ('\u{11180}', '\u{111c4}'), + ('\u{111c9}', '\u{111cc}'), + ('\u{111ce}', '\u{111da}'), + ('\u{111dc}', '\u{111dc}'), + ('\u{11200}', '\u{11211}'), + ('\u{11213}', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), + ('\u{11280}', '\u{11286}'), + ('\u{11288}', '\u{11288}'), + ('\u{1128a}', '\u{1128d}'), + ('\u{1128f}', '\u{1129d}'), + ('\u{1129f}', '\u{112a8}'), + ('\u{112b0}', '\u{112ea}'), + ('\u{112f0}', '\u{112f9}'), + ('\u{11300}', '\u{11303}'), + ('\u{11305}', '\u{1130c}'), + ('\u{1130f}', '\u{11310}'), + ('\u{11313}', '\u{11328}'), + ('\u{1132a}', '\u{11330}'), + ('\u{11332}', '\u{11333}'), + ('\u{11335}', '\u{11339}'), + ('\u{1133b}', '\u{11344}'), + ('\u{11347}', '\u{11348}'), + ('\u{1134b}', '\u{1134d}'), + ('\u{11350}', '\u{11350}'), + ('\u{11357}', '\u{11357}'), + ('\u{1135d}', '\u{11363}'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('\u{11400}', '\u{1144a}'), + ('\u{11450}', '\u{11459}'), + ('\u{1145e}', '\u{11461}'), + ('\u{11480}', '\u{114c5}'), + ('\u{114c7}', '\u{114c7}'), + ('\u{114d0}', '\u{114d9}'), + ('\u{11580}', '\u{115b5}'), + ('\u{115b8}', '\u{115c0}'), + ('\u{115d8}', '\u{115dd}'), + ('\u{11600}', '\u{11640}'), + ('\u{11644}', '\u{11644}'), + ('\u{11650}', '\u{11659}'), + ('\u{11680}', '\u{116b8}'), + ('\u{116c0}', '\u{116c9}'), + ('\u{11700}', '\u{1171a}'), + ('\u{1171d}', '\u{1172b}'), + ('\u{11730}', '\u{11739}'), + ('\u{11800}', '\u{1183a}'), + ('\u{118a0}', '\u{118e9}'), + ('\u{118ff}', '\u{11906}'), + ('\u{11909}', '\u{11909}'), + ('\u{1190c}', '\u{11913}'), + ('\u{11915}', '\u{11916}'), + ('\u{11918}', '\u{11935}'), + ('\u{11937}', '\u{11938}'), + ('\u{1193b}', '\u{11943}'), + ('\u{11950}', '\u{11959}'), + ('\u{119a0}', '\u{119a7}'), + ('\u{119aa}', '\u{119d7}'), + ('\u{119da}', '\u{119e1}'), + ('\u{119e3}', '\u{119e4}'), + ('\u{11a00}', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), + ('\u{11a50}', '\u{11a99}'), + ('\u{11a9d}', '\u{11a9d}'), + ('\u{11ac0}', '\u{11af8}'), + ('\u{11c00}', '\u{11c08}'), + ('\u{11c0a}', '\u{11c36}'), + ('\u{11c38}', '\u{11c40}'), + ('\u{11c50}', '\u{11c59}'), + ('\u{11c72}', '\u{11c8f}'), + ('\u{11c92}', '\u{11ca7}'), + ('\u{11ca9}', '\u{11cb6}'), + ('\u{11d00}', '\u{11d06}'), + ('\u{11d08}', '\u{11d09}'), + ('\u{11d0b}', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d47}'), + ('\u{11d50}', '\u{11d59}'), + ('\u{11d60}', '\u{11d65}'), + ('\u{11d67}', '\u{11d68}'), + ('\u{11d6a}', '\u{11d8e}'), + ('\u{11d90}', '\u{11d91}'), + ('\u{11d93}', '\u{11d98}'), + ('\u{11da0}', '\u{11da9}'), + ('\u{11ee0}', '\u{11ef6}'), + ('\u{11fb0}', '\u{11fb0}'), + ('\u{12000}', '\u{12399}'), + ('\u{12400}', '\u{1246e}'), + ('\u{12480}', '\u{12543}'), + ('\u{13000}', '\u{1342e}'), + ('\u{14400}', '\u{14646}'), + ('\u{16800}', '\u{16a38}'), + ('\u{16a40}', '\u{16a5e}'), + ('\u{16a60}', '\u{16a69}'), + ('\u{16ad0}', '\u{16aed}'), + ('\u{16af0}', '\u{16af4}'), + ('\u{16b00}', '\u{16b36}'), + ('\u{16b40}', '\u{16b43}'), + ('\u{16b50}', '\u{16b59}'), + ('\u{16b63}', '\u{16b77}'), + ('\u{16b7d}', '\u{16b8f}'), + ('\u{16e40}', '\u{16e7f}'), + ('\u{16f00}', '\u{16f4a}'), + ('\u{16f4f}', '\u{16f87}'), + ('\u{16f8f}', '\u{16f9f}'), + ('\u{16fe0}', '\u{16fe1}'), + ('\u{16fe3}', '\u{16fe4}'), + ('\u{16ff0}', '\u{16ff1}'), + ('\u{17000}', '\u{187f7}'), + ('\u{18800}', '\u{18cd5}'), + ('\u{18d00}', '\u{18d08}'), + ('\u{1b000}', '\u{1b11e}'), + ('\u{1b150}', '\u{1b152}'), + ('\u{1b164}', '\u{1b167}'), + ('\u{1b170}', '\u{1b2fb}'), + ('\u{1bc00}', '\u{1bc6a}'), + ('\u{1bc70}', '\u{1bc7c}'), + ('\u{1bc80}', '\u{1bc88}'), + ('\u{1bc90}', '\u{1bc99}'), + ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1d165}', '\u{1d169}'), + ('\u{1d16d}', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), + ('\u{1d400}', '\u{1d454}'), + ('\u{1d456}', '\u{1d49c}'), + ('\u{1d49e}', '\u{1d49f}'), + ('\u{1d4a2}', '\u{1d4a2}'), + ('\u{1d4a5}', '\u{1d4a6}'), + ('\u{1d4a9}', '\u{1d4ac}'), + ('\u{1d4ae}', '\u{1d4b9}'), + ('\u{1d4bb}', '\u{1d4bb}'), + ('\u{1d4bd}', '\u{1d4c3}'), + ('\u{1d4c5}', '\u{1d505}'), + ('\u{1d507}', '\u{1d50a}'), + ('\u{1d50d}', '\u{1d514}'), + ('\u{1d516}', '\u{1d51c}'), + ('\u{1d51e}', '\u{1d539}'), + ('\u{1d53b}', '\u{1d53e}'), + ('\u{1d540}', '\u{1d544}'), + ('\u{1d546}', '\u{1d546}'), + ('\u{1d54a}', '\u{1d550}'), + ('\u{1d552}', '\u{1d6a5}'), + ('\u{1d6a8}', '\u{1d6c0}'), + ('\u{1d6c2}', '\u{1d6da}'), + ('\u{1d6dc}', '\u{1d6fa}'), + ('\u{1d6fc}', '\u{1d714}'), + ('\u{1d716}', '\u{1d734}'), + ('\u{1d736}', '\u{1d74e}'), + ('\u{1d750}', '\u{1d76e}'), + ('\u{1d770}', '\u{1d788}'), + ('\u{1d78a}', '\u{1d7a8}'), + ('\u{1d7aa}', '\u{1d7c2}'), + ('\u{1d7c4}', '\u{1d7cb}'), + ('\u{1d7ce}', '\u{1d7ff}'), + ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), + ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), + ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('\u{1e100}', '\u{1e12c}'), + ('\u{1e130}', '\u{1e13d}'), + ('\u{1e140}', '\u{1e149}'), + ('\u{1e14e}', '\u{1e14e}'), + ('\u{1e2c0}', '\u{1e2f9}'), + ('\u{1e800}', '\u{1e8c4}'), + ('\u{1e8d0}', '\u{1e8d6}'), + ('\u{1e900}', '\u{1e94b}'), + ('\u{1e950}', '\u{1e959}'), + ('\u{1ee00}', '\u{1ee03}'), + ('\u{1ee05}', '\u{1ee1f}'), + ('\u{1ee21}', '\u{1ee22}'), + ('\u{1ee24}', '\u{1ee24}'), + ('\u{1ee27}', '\u{1ee27}'), + ('\u{1ee29}', '\u{1ee32}'), + ('\u{1ee34}', '\u{1ee37}'), + ('\u{1ee39}', '\u{1ee39}'), + ('\u{1ee3b}', '\u{1ee3b}'), + ('\u{1ee42}', '\u{1ee42}'), + ('\u{1ee47}', '\u{1ee47}'), + ('\u{1ee49}', '\u{1ee49}'), + ('\u{1ee4b}', '\u{1ee4b}'), + ('\u{1ee4d}', '\u{1ee4f}'), + ('\u{1ee51}', '\u{1ee52}'), + ('\u{1ee54}', '\u{1ee54}'), + ('\u{1ee57}', '\u{1ee57}'), + ('\u{1ee59}', '\u{1ee59}'), + ('\u{1ee5b}', '\u{1ee5b}'), + ('\u{1ee5d}', '\u{1ee5d}'), + ('\u{1ee5f}', '\u{1ee5f}'), + ('\u{1ee61}', '\u{1ee62}'), + ('\u{1ee64}', '\u{1ee64}'), + ('\u{1ee67}', '\u{1ee6a}'), + ('\u{1ee6c}', '\u{1ee72}'), + ('\u{1ee74}', '\u{1ee77}'), + ('\u{1ee79}', '\u{1ee7c}'), + ('\u{1ee7e}', '\u{1ee7e}'), + ('\u{1ee80}', '\u{1ee89}'), + ('\u{1ee8b}', '\u{1ee9b}'), + ('\u{1eea1}', '\u{1eea3}'), + ('\u{1eea5}', '\u{1eea9}'), + ('\u{1eeab}', '\u{1eebb}'), + ('\u{1fbf0}', '\u{1fbf9}'), + ('\u{20000}', '\u{2a6dd}'), + ('\u{2a700}', '\u{2b734}'), + ('\u{2b740}', '\u{2b81d}'), + ('\u{2b820}', '\u{2cea1}'), + ('\u{2ceb0}', '\u{2ebe0}'), + ('\u{2f800}', '\u{2fa1d}'), + ('\u{30000}', '\u{3134a}'), + ('\u{e0100}', '\u{e01ef}'), + ]; + + pub fn XID_Continue(c: char) -> bool { + super::bsearch_range_table(c, XID_Continue_table) + } + + pub const XID_Start_table: &[(char, char)] = &[ + ('\u{41}', '\u{5a}'), + ('\u{61}', '\u{7a}'), + ('\u{aa}', '\u{aa}'), + ('\u{b5}', '\u{b5}'), + ('\u{ba}', '\u{ba}'), + ('\u{c0}', '\u{d6}'), + ('\u{d8}', '\u{f6}'), + ('\u{f8}', '\u{2c1}'), + ('\u{2c6}', '\u{2d1}'), + ('\u{2e0}', '\u{2e4}'), + ('\u{2ec}', '\u{2ec}'), + ('\u{2ee}', '\u{2ee}'), + ('\u{370}', '\u{374}'), + ('\u{376}', '\u{377}'), + ('\u{37b}', '\u{37d}'), + ('\u{37f}', '\u{37f}'), + ('\u{386}', '\u{386}'), + ('\u{388}', '\u{38a}'), + ('\u{38c}', '\u{38c}'), + ('\u{38e}', '\u{3a1}'), + ('\u{3a3}', '\u{3f5}'), + ('\u{3f7}', '\u{481}'), + ('\u{48a}', '\u{52f}'), + ('\u{531}', '\u{556}'), + ('\u{559}', '\u{559}'), + ('\u{560}', '\u{588}'), + ('\u{5d0}', '\u{5ea}'), + ('\u{5ef}', '\u{5f2}'), + ('\u{620}', '\u{64a}'), + ('\u{66e}', '\u{66f}'), + ('\u{671}', '\u{6d3}'), + ('\u{6d5}', '\u{6d5}'), + ('\u{6e5}', '\u{6e6}'), + ('\u{6ee}', '\u{6ef}'), + ('\u{6fa}', '\u{6fc}'), + ('\u{6ff}', '\u{6ff}'), + ('\u{710}', '\u{710}'), + ('\u{712}', '\u{72f}'), + ('\u{74d}', '\u{7a5}'), + ('\u{7b1}', '\u{7b1}'), + ('\u{7ca}', '\u{7ea}'), + ('\u{7f4}', '\u{7f5}'), + ('\u{7fa}', '\u{7fa}'), + ('\u{800}', '\u{815}'), + ('\u{81a}', '\u{81a}'), + ('\u{824}', '\u{824}'), + ('\u{828}', '\u{828}'), + ('\u{840}', '\u{858}'), + ('\u{860}', '\u{86a}'), + ('\u{8a0}', '\u{8b4}'), + ('\u{8b6}', '\u{8c7}'), + ('\u{904}', '\u{939}'), + ('\u{93d}', '\u{93d}'), + ('\u{950}', '\u{950}'), + ('\u{958}', '\u{961}'), + ('\u{971}', '\u{980}'), + ('\u{985}', '\u{98c}'), + ('\u{98f}', '\u{990}'), + ('\u{993}', '\u{9a8}'), + ('\u{9aa}', '\u{9b0}'), + ('\u{9b2}', '\u{9b2}'), + ('\u{9b6}', '\u{9b9}'), + ('\u{9bd}', '\u{9bd}'), + ('\u{9ce}', '\u{9ce}'), + ('\u{9dc}', '\u{9dd}'), + ('\u{9df}', '\u{9e1}'), + ('\u{9f0}', '\u{9f1}'), + ('\u{9fc}', '\u{9fc}'), + ('\u{a05}', '\u{a0a}'), + ('\u{a0f}', '\u{a10}'), + ('\u{a13}', '\u{a28}'), + ('\u{a2a}', '\u{a30}'), + ('\u{a32}', '\u{a33}'), + ('\u{a35}', '\u{a36}'), + ('\u{a38}', '\u{a39}'), + ('\u{a59}', '\u{a5c}'), + ('\u{a5e}', '\u{a5e}'), + ('\u{a72}', '\u{a74}'), + ('\u{a85}', '\u{a8d}'), + ('\u{a8f}', '\u{a91}'), + ('\u{a93}', '\u{aa8}'), + ('\u{aaa}', '\u{ab0}'), + ('\u{ab2}', '\u{ab3}'), + ('\u{ab5}', '\u{ab9}'), + ('\u{abd}', '\u{abd}'), + ('\u{ad0}', '\u{ad0}'), + ('\u{ae0}', '\u{ae1}'), + ('\u{af9}', '\u{af9}'), + ('\u{b05}', '\u{b0c}'), + ('\u{b0f}', '\u{b10}'), + ('\u{b13}', '\u{b28}'), + ('\u{b2a}', '\u{b30}'), + ('\u{b32}', '\u{b33}'), + ('\u{b35}', '\u{b39}'), + ('\u{b3d}', '\u{b3d}'), + ('\u{b5c}', '\u{b5d}'), + ('\u{b5f}', '\u{b61}'), + ('\u{b71}', '\u{b71}'), + ('\u{b83}', '\u{b83}'), + ('\u{b85}', '\u{b8a}'), + ('\u{b8e}', '\u{b90}'), + ('\u{b92}', '\u{b95}'), + ('\u{b99}', '\u{b9a}'), + ('\u{b9c}', '\u{b9c}'), + ('\u{b9e}', '\u{b9f}'), + ('\u{ba3}', '\u{ba4}'), + ('\u{ba8}', '\u{baa}'), + ('\u{bae}', '\u{bb9}'), + ('\u{bd0}', '\u{bd0}'), + ('\u{c05}', '\u{c0c}'), + ('\u{c0e}', '\u{c10}'), + ('\u{c12}', '\u{c28}'), + ('\u{c2a}', '\u{c39}'), + ('\u{c3d}', '\u{c3d}'), + ('\u{c58}', '\u{c5a}'), + ('\u{c60}', '\u{c61}'), + ('\u{c80}', '\u{c80}'), + ('\u{c85}', '\u{c8c}'), + ('\u{c8e}', '\u{c90}'), + ('\u{c92}', '\u{ca8}'), + ('\u{caa}', '\u{cb3}'), + ('\u{cb5}', '\u{cb9}'), + ('\u{cbd}', '\u{cbd}'), + ('\u{cde}', '\u{cde}'), + ('\u{ce0}', '\u{ce1}'), + ('\u{cf1}', '\u{cf2}'), + ('\u{d04}', '\u{d0c}'), + ('\u{d0e}', '\u{d10}'), + ('\u{d12}', '\u{d3a}'), + ('\u{d3d}', '\u{d3d}'), + ('\u{d4e}', '\u{d4e}'), + ('\u{d54}', '\u{d56}'), + ('\u{d5f}', '\u{d61}'), + ('\u{d7a}', '\u{d7f}'), + ('\u{d85}', '\u{d96}'), + ('\u{d9a}', '\u{db1}'), + ('\u{db3}', '\u{dbb}'), + ('\u{dbd}', '\u{dbd}'), + ('\u{dc0}', '\u{dc6}'), + ('\u{e01}', '\u{e30}'), + ('\u{e32}', '\u{e32}'), + ('\u{e40}', '\u{e46}'), + ('\u{e81}', '\u{e82}'), + ('\u{e84}', '\u{e84}'), + ('\u{e86}', '\u{e8a}'), + ('\u{e8c}', '\u{ea3}'), + ('\u{ea5}', '\u{ea5}'), + ('\u{ea7}', '\u{eb0}'), + ('\u{eb2}', '\u{eb2}'), + ('\u{ebd}', '\u{ebd}'), + ('\u{ec0}', '\u{ec4}'), + ('\u{ec6}', '\u{ec6}'), + ('\u{edc}', '\u{edf}'), + ('\u{f00}', '\u{f00}'), + ('\u{f40}', '\u{f47}'), + ('\u{f49}', '\u{f6c}'), + ('\u{f88}', '\u{f8c}'), + ('\u{1000}', '\u{102a}'), + ('\u{103f}', '\u{103f}'), + ('\u{1050}', '\u{1055}'), + ('\u{105a}', '\u{105d}'), + ('\u{1061}', '\u{1061}'), + ('\u{1065}', '\u{1066}'), + ('\u{106e}', '\u{1070}'), + ('\u{1075}', '\u{1081}'), + ('\u{108e}', '\u{108e}'), + ('\u{10a0}', '\u{10c5}'), + ('\u{10c7}', '\u{10c7}'), + ('\u{10cd}', '\u{10cd}'), + ('\u{10d0}', '\u{10fa}'), + ('\u{10fc}', '\u{1248}'), + ('\u{124a}', '\u{124d}'), + ('\u{1250}', '\u{1256}'), + ('\u{1258}', '\u{1258}'), + ('\u{125a}', '\u{125d}'), + ('\u{1260}', '\u{1288}'), + ('\u{128a}', '\u{128d}'), + ('\u{1290}', '\u{12b0}'), + ('\u{12b2}', '\u{12b5}'), + ('\u{12b8}', '\u{12be}'), + ('\u{12c0}', '\u{12c0}'), + ('\u{12c2}', '\u{12c5}'), + ('\u{12c8}', '\u{12d6}'), + ('\u{12d8}', '\u{1310}'), + ('\u{1312}', '\u{1315}'), + ('\u{1318}', '\u{135a}'), + ('\u{1380}', '\u{138f}'), + ('\u{13a0}', '\u{13f5}'), + ('\u{13f8}', '\u{13fd}'), + ('\u{1401}', '\u{166c}'), + ('\u{166f}', '\u{167f}'), + ('\u{1681}', '\u{169a}'), + ('\u{16a0}', '\u{16ea}'), + ('\u{16ee}', '\u{16f8}'), + ('\u{1700}', '\u{170c}'), + ('\u{170e}', '\u{1711}'), + ('\u{1720}', '\u{1731}'), + ('\u{1740}', '\u{1751}'), + ('\u{1760}', '\u{176c}'), + ('\u{176e}', '\u{1770}'), + ('\u{1780}', '\u{17b3}'), + ('\u{17d7}', '\u{17d7}'), + ('\u{17dc}', '\u{17dc}'), + ('\u{1820}', '\u{1878}'), + ('\u{1880}', '\u{18a8}'), + ('\u{18aa}', '\u{18aa}'), + ('\u{18b0}', '\u{18f5}'), + ('\u{1900}', '\u{191e}'), + ('\u{1950}', '\u{196d}'), + ('\u{1970}', '\u{1974}'), + ('\u{1980}', '\u{19ab}'), + ('\u{19b0}', '\u{19c9}'), + ('\u{1a00}', '\u{1a16}'), + ('\u{1a20}', '\u{1a54}'), + ('\u{1aa7}', '\u{1aa7}'), + ('\u{1b05}', '\u{1b33}'), + ('\u{1b45}', '\u{1b4b}'), + ('\u{1b83}', '\u{1ba0}'), + ('\u{1bae}', '\u{1baf}'), + ('\u{1bba}', '\u{1be5}'), + ('\u{1c00}', '\u{1c23}'), + ('\u{1c4d}', '\u{1c4f}'), + ('\u{1c5a}', '\u{1c7d}'), + ('\u{1c80}', '\u{1c88}'), + ('\u{1c90}', '\u{1cba}'), + ('\u{1cbd}', '\u{1cbf}'), + ('\u{1ce9}', '\u{1cec}'), + ('\u{1cee}', '\u{1cf3}'), + ('\u{1cf5}', '\u{1cf6}'), + ('\u{1cfa}', '\u{1cfa}'), + ('\u{1d00}', '\u{1dbf}'), + ('\u{1e00}', '\u{1f15}'), + ('\u{1f18}', '\u{1f1d}'), + ('\u{1f20}', '\u{1f45}'), + ('\u{1f48}', '\u{1f4d}'), + ('\u{1f50}', '\u{1f57}'), + ('\u{1f59}', '\u{1f59}'), + ('\u{1f5b}', '\u{1f5b}'), + ('\u{1f5d}', '\u{1f5d}'), + ('\u{1f5f}', '\u{1f7d}'), + ('\u{1f80}', '\u{1fb4}'), + ('\u{1fb6}', '\u{1fbc}'), + ('\u{1fbe}', '\u{1fbe}'), + ('\u{1fc2}', '\u{1fc4}'), + ('\u{1fc6}', '\u{1fcc}'), + ('\u{1fd0}', '\u{1fd3}'), + ('\u{1fd6}', '\u{1fdb}'), + ('\u{1fe0}', '\u{1fec}'), + ('\u{1ff2}', '\u{1ff4}'), + ('\u{1ff6}', '\u{1ffc}'), + ('\u{2071}', '\u{2071}'), + ('\u{207f}', '\u{207f}'), + ('\u{2090}', '\u{209c}'), + ('\u{2102}', '\u{2102}'), + ('\u{2107}', '\u{2107}'), + ('\u{210a}', '\u{2113}'), + ('\u{2115}', '\u{2115}'), + ('\u{2118}', '\u{211d}'), + ('\u{2124}', '\u{2124}'), + ('\u{2126}', '\u{2126}'), + ('\u{2128}', '\u{2128}'), + ('\u{212a}', '\u{2139}'), + ('\u{213c}', '\u{213f}'), + ('\u{2145}', '\u{2149}'), + ('\u{214e}', '\u{214e}'), + ('\u{2160}', '\u{2188}'), + ('\u{2c00}', '\u{2c2e}'), + ('\u{2c30}', '\u{2c5e}'), + ('\u{2c60}', '\u{2ce4}'), + ('\u{2ceb}', '\u{2cee}'), + ('\u{2cf2}', '\u{2cf3}'), + ('\u{2d00}', '\u{2d25}'), + ('\u{2d27}', '\u{2d27}'), + ('\u{2d2d}', '\u{2d2d}'), + ('\u{2d30}', '\u{2d67}'), + ('\u{2d6f}', '\u{2d6f}'), + ('\u{2d80}', '\u{2d96}'), + ('\u{2da0}', '\u{2da6}'), + ('\u{2da8}', '\u{2dae}'), + ('\u{2db0}', '\u{2db6}'), + ('\u{2db8}', '\u{2dbe}'), + ('\u{2dc0}', '\u{2dc6}'), + ('\u{2dc8}', '\u{2dce}'), + ('\u{2dd0}', '\u{2dd6}'), + ('\u{2dd8}', '\u{2dde}'), + ('\u{3005}', '\u{3007}'), + ('\u{3021}', '\u{3029}'), + ('\u{3031}', '\u{3035}'), + ('\u{3038}', '\u{303c}'), + ('\u{3041}', '\u{3096}'), + ('\u{309d}', '\u{309f}'), + ('\u{30a1}', '\u{30fa}'), + ('\u{30fc}', '\u{30ff}'), + ('\u{3105}', '\u{312f}'), + ('\u{3131}', '\u{318e}'), + ('\u{31a0}', '\u{31bf}'), + ('\u{31f0}', '\u{31ff}'), + ('\u{3400}', '\u{4dbf}'), + ('\u{4e00}', '\u{9ffc}'), + ('\u{a000}', '\u{a48c}'), + ('\u{a4d0}', '\u{a4fd}'), + ('\u{a500}', '\u{a60c}'), + ('\u{a610}', '\u{a61f}'), + ('\u{a62a}', '\u{a62b}'), + ('\u{a640}', '\u{a66e}'), + ('\u{a67f}', '\u{a69d}'), + ('\u{a6a0}', '\u{a6ef}'), + ('\u{a717}', '\u{a71f}'), + ('\u{a722}', '\u{a788}'), + ('\u{a78b}', '\u{a7bf}'), + ('\u{a7c2}', '\u{a7ca}'), + ('\u{a7f5}', '\u{a801}'), + ('\u{a803}', '\u{a805}'), + ('\u{a807}', '\u{a80a}'), + ('\u{a80c}', '\u{a822}'), + ('\u{a840}', '\u{a873}'), + ('\u{a882}', '\u{a8b3}'), + ('\u{a8f2}', '\u{a8f7}'), + ('\u{a8fb}', '\u{a8fb}'), + ('\u{a8fd}', '\u{a8fe}'), + ('\u{a90a}', '\u{a925}'), + ('\u{a930}', '\u{a946}'), + ('\u{a960}', '\u{a97c}'), + ('\u{a984}', '\u{a9b2}'), + ('\u{a9cf}', '\u{a9cf}'), + ('\u{a9e0}', '\u{a9e4}'), + ('\u{a9e6}', '\u{a9ef}'), + ('\u{a9fa}', '\u{a9fe}'), + ('\u{aa00}', '\u{aa28}'), + ('\u{aa40}', '\u{aa42}'), + ('\u{aa44}', '\u{aa4b}'), + ('\u{aa60}', '\u{aa76}'), + ('\u{aa7a}', '\u{aa7a}'), + ('\u{aa7e}', '\u{aaaf}'), + ('\u{aab1}', '\u{aab1}'), + ('\u{aab5}', '\u{aab6}'), + ('\u{aab9}', '\u{aabd}'), + ('\u{aac0}', '\u{aac0}'), + ('\u{aac2}', '\u{aac2}'), + ('\u{aadb}', '\u{aadd}'), + ('\u{aae0}', '\u{aaea}'), + ('\u{aaf2}', '\u{aaf4}'), + ('\u{ab01}', '\u{ab06}'), + ('\u{ab09}', '\u{ab0e}'), + ('\u{ab11}', '\u{ab16}'), + ('\u{ab20}', '\u{ab26}'), + ('\u{ab28}', '\u{ab2e}'), + ('\u{ab30}', '\u{ab5a}'), + ('\u{ab5c}', '\u{ab69}'), + ('\u{ab70}', '\u{abe2}'), + ('\u{ac00}', '\u{d7a3}'), + ('\u{d7b0}', '\u{d7c6}'), + ('\u{d7cb}', '\u{d7fb}'), + ('\u{f900}', '\u{fa6d}'), + ('\u{fa70}', '\u{fad9}'), + ('\u{fb00}', '\u{fb06}'), + ('\u{fb13}', '\u{fb17}'), + ('\u{fb1d}', '\u{fb1d}'), + ('\u{fb1f}', '\u{fb28}'), + ('\u{fb2a}', '\u{fb36}'), + ('\u{fb38}', '\u{fb3c}'), + ('\u{fb3e}', '\u{fb3e}'), + ('\u{fb40}', '\u{fb41}'), + ('\u{fb43}', '\u{fb44}'), + ('\u{fb46}', '\u{fbb1}'), + ('\u{fbd3}', '\u{fc5d}'), + ('\u{fc64}', '\u{fd3d}'), + ('\u{fd50}', '\u{fd8f}'), + ('\u{fd92}', '\u{fdc7}'), + ('\u{fdf0}', '\u{fdf9}'), + ('\u{fe71}', '\u{fe71}'), + ('\u{fe73}', '\u{fe73}'), + ('\u{fe77}', '\u{fe77}'), + ('\u{fe79}', '\u{fe79}'), + ('\u{fe7b}', '\u{fe7b}'), + ('\u{fe7d}', '\u{fe7d}'), + ('\u{fe7f}', '\u{fefc}'), + ('\u{ff21}', '\u{ff3a}'), + ('\u{ff41}', '\u{ff5a}'), + ('\u{ff66}', '\u{ff9d}'), + ('\u{ffa0}', '\u{ffbe}'), + ('\u{ffc2}', '\u{ffc7}'), + ('\u{ffca}', '\u{ffcf}'), + ('\u{ffd2}', '\u{ffd7}'), + ('\u{ffda}', '\u{ffdc}'), + ('\u{10000}', '\u{1000b}'), + ('\u{1000d}', '\u{10026}'), + ('\u{10028}', '\u{1003a}'), + ('\u{1003c}', '\u{1003d}'), + ('\u{1003f}', '\u{1004d}'), + ('\u{10050}', '\u{1005d}'), + ('\u{10080}', '\u{100fa}'), + ('\u{10140}', '\u{10174}'), + ('\u{10280}', '\u{1029c}'), + ('\u{102a0}', '\u{102d0}'), + ('\u{10300}', '\u{1031f}'), + ('\u{1032d}', '\u{1034a}'), + ('\u{10350}', '\u{10375}'), + ('\u{10380}', '\u{1039d}'), + ('\u{103a0}', '\u{103c3}'), + ('\u{103c8}', '\u{103cf}'), + ('\u{103d1}', '\u{103d5}'), + ('\u{10400}', '\u{1049d}'), + ('\u{104b0}', '\u{104d3}'), + ('\u{104d8}', '\u{104fb}'), + ('\u{10500}', '\u{10527}'), + ('\u{10530}', '\u{10563}'), + ('\u{10600}', '\u{10736}'), + ('\u{10740}', '\u{10755}'), + ('\u{10760}', '\u{10767}'), + ('\u{10800}', '\u{10805}'), + ('\u{10808}', '\u{10808}'), + ('\u{1080a}', '\u{10835}'), + ('\u{10837}', '\u{10838}'), + ('\u{1083c}', '\u{1083c}'), + ('\u{1083f}', '\u{10855}'), + ('\u{10860}', '\u{10876}'), + ('\u{10880}', '\u{1089e}'), + ('\u{108e0}', '\u{108f2}'), + ('\u{108f4}', '\u{108f5}'), + ('\u{10900}', '\u{10915}'), + ('\u{10920}', '\u{10939}'), + ('\u{10980}', '\u{109b7}'), + ('\u{109be}', '\u{109bf}'), + ('\u{10a00}', '\u{10a00}'), + ('\u{10a10}', '\u{10a13}'), + ('\u{10a15}', '\u{10a17}'), + ('\u{10a19}', '\u{10a35}'), + ('\u{10a60}', '\u{10a7c}'), + ('\u{10a80}', '\u{10a9c}'), + ('\u{10ac0}', '\u{10ac7}'), + ('\u{10ac9}', '\u{10ae4}'), + ('\u{10b00}', '\u{10b35}'), + ('\u{10b40}', '\u{10b55}'), + ('\u{10b60}', '\u{10b72}'), + ('\u{10b80}', '\u{10b91}'), + ('\u{10c00}', '\u{10c48}'), + ('\u{10c80}', '\u{10cb2}'), + ('\u{10cc0}', '\u{10cf2}'), + ('\u{10d00}', '\u{10d23}'), + ('\u{10e80}', '\u{10ea9}'), + ('\u{10eb0}', '\u{10eb1}'), + ('\u{10f00}', '\u{10f1c}'), + ('\u{10f27}', '\u{10f27}'), + ('\u{10f30}', '\u{10f45}'), + ('\u{10fb0}', '\u{10fc4}'), + ('\u{10fe0}', '\u{10ff6}'), + ('\u{11003}', '\u{11037}'), + ('\u{11083}', '\u{110af}'), + ('\u{110d0}', '\u{110e8}'), + ('\u{11103}', '\u{11126}'), + ('\u{11144}', '\u{11144}'), + ('\u{11147}', '\u{11147}'), + ('\u{11150}', '\u{11172}'), + ('\u{11176}', '\u{11176}'), + ('\u{11183}', '\u{111b2}'), + ('\u{111c1}', '\u{111c4}'), + ('\u{111da}', '\u{111da}'), + ('\u{111dc}', '\u{111dc}'), + ('\u{11200}', '\u{11211}'), + ('\u{11213}', '\u{1122b}'), + ('\u{11280}', '\u{11286}'), + ('\u{11288}', '\u{11288}'), + ('\u{1128a}', '\u{1128d}'), + ('\u{1128f}', '\u{1129d}'), + ('\u{1129f}', '\u{112a8}'), + ('\u{112b0}', '\u{112de}'), + ('\u{11305}', '\u{1130c}'), + ('\u{1130f}', '\u{11310}'), + ('\u{11313}', '\u{11328}'), + ('\u{1132a}', '\u{11330}'), + ('\u{11332}', '\u{11333}'), + ('\u{11335}', '\u{11339}'), + ('\u{1133d}', '\u{1133d}'), + ('\u{11350}', '\u{11350}'), + ('\u{1135d}', '\u{11361}'), + ('\u{11400}', '\u{11434}'), + ('\u{11447}', '\u{1144a}'), + ('\u{1145f}', '\u{11461}'), + ('\u{11480}', '\u{114af}'), + ('\u{114c4}', '\u{114c5}'), + ('\u{114c7}', '\u{114c7}'), + ('\u{11580}', '\u{115ae}'), + ('\u{115d8}', '\u{115db}'), + ('\u{11600}', '\u{1162f}'), + ('\u{11644}', '\u{11644}'), + ('\u{11680}', '\u{116aa}'), + ('\u{116b8}', '\u{116b8}'), + ('\u{11700}', '\u{1171a}'), + ('\u{11800}', '\u{1182b}'), + ('\u{118a0}', '\u{118df}'), + ('\u{118ff}', '\u{11906}'), + ('\u{11909}', '\u{11909}'), + ('\u{1190c}', '\u{11913}'), + ('\u{11915}', '\u{11916}'), + ('\u{11918}', '\u{1192f}'), + ('\u{1193f}', '\u{1193f}'), + ('\u{11941}', '\u{11941}'), + ('\u{119a0}', '\u{119a7}'), + ('\u{119aa}', '\u{119d0}'), + ('\u{119e1}', '\u{119e1}'), + ('\u{119e3}', '\u{119e3}'), + ('\u{11a00}', '\u{11a00}'), + ('\u{11a0b}', '\u{11a32}'), + ('\u{11a3a}', '\u{11a3a}'), + ('\u{11a50}', '\u{11a50}'), + ('\u{11a5c}', '\u{11a89}'), + ('\u{11a9d}', '\u{11a9d}'), + ('\u{11ac0}', '\u{11af8}'), + ('\u{11c00}', '\u{11c08}'), + ('\u{11c0a}', '\u{11c2e}'), + ('\u{11c40}', '\u{11c40}'), + ('\u{11c72}', '\u{11c8f}'), + ('\u{11d00}', '\u{11d06}'), + ('\u{11d08}', '\u{11d09}'), + ('\u{11d0b}', '\u{11d30}'), + ('\u{11d46}', '\u{11d46}'), + ('\u{11d60}', '\u{11d65}'), + ('\u{11d67}', '\u{11d68}'), + ('\u{11d6a}', '\u{11d89}'), + ('\u{11d98}', '\u{11d98}'), + ('\u{11ee0}', '\u{11ef2}'), + ('\u{11fb0}', '\u{11fb0}'), + ('\u{12000}', '\u{12399}'), + ('\u{12400}', '\u{1246e}'), + ('\u{12480}', '\u{12543}'), + ('\u{13000}', '\u{1342e}'), + ('\u{14400}', '\u{14646}'), + ('\u{16800}', '\u{16a38}'), + ('\u{16a40}', '\u{16a5e}'), + ('\u{16ad0}', '\u{16aed}'), + ('\u{16b00}', '\u{16b2f}'), + ('\u{16b40}', '\u{16b43}'), + ('\u{16b63}', '\u{16b77}'), + ('\u{16b7d}', '\u{16b8f}'), + ('\u{16e40}', '\u{16e7f}'), + ('\u{16f00}', '\u{16f4a}'), + ('\u{16f50}', '\u{16f50}'), + ('\u{16f93}', '\u{16f9f}'), + ('\u{16fe0}', '\u{16fe1}'), + ('\u{16fe3}', '\u{16fe3}'), + ('\u{17000}', '\u{187f7}'), + ('\u{18800}', '\u{18cd5}'), + ('\u{18d00}', '\u{18d08}'), + ('\u{1b000}', '\u{1b11e}'), + ('\u{1b150}', '\u{1b152}'), + ('\u{1b164}', '\u{1b167}'), + ('\u{1b170}', '\u{1b2fb}'), + ('\u{1bc00}', '\u{1bc6a}'), + ('\u{1bc70}', '\u{1bc7c}'), + ('\u{1bc80}', '\u{1bc88}'), + ('\u{1bc90}', '\u{1bc99}'), + ('\u{1d400}', '\u{1d454}'), + ('\u{1d456}', '\u{1d49c}'), + ('\u{1d49e}', '\u{1d49f}'), + ('\u{1d4a2}', '\u{1d4a2}'), + ('\u{1d4a5}', '\u{1d4a6}'), + ('\u{1d4a9}', '\u{1d4ac}'), + ('\u{1d4ae}', '\u{1d4b9}'), + ('\u{1d4bb}', '\u{1d4bb}'), + ('\u{1d4bd}', '\u{1d4c3}'), + ('\u{1d4c5}', '\u{1d505}'), + ('\u{1d507}', '\u{1d50a}'), + ('\u{1d50d}', '\u{1d514}'), + ('\u{1d516}', '\u{1d51c}'), + ('\u{1d51e}', '\u{1d539}'), + ('\u{1d53b}', '\u{1d53e}'), + ('\u{1d540}', '\u{1d544}'), + ('\u{1d546}', '\u{1d546}'), + ('\u{1d54a}', '\u{1d550}'), + ('\u{1d552}', '\u{1d6a5}'), + ('\u{1d6a8}', '\u{1d6c0}'), + ('\u{1d6c2}', '\u{1d6da}'), + ('\u{1d6dc}', '\u{1d6fa}'), + ('\u{1d6fc}', '\u{1d714}'), + ('\u{1d716}', '\u{1d734}'), + ('\u{1d736}', '\u{1d74e}'), + ('\u{1d750}', '\u{1d76e}'), + ('\u{1d770}', '\u{1d788}'), + ('\u{1d78a}', '\u{1d7a8}'), + ('\u{1d7aa}', '\u{1d7c2}'), + ('\u{1d7c4}', '\u{1d7cb}'), + ('\u{1e100}', '\u{1e12c}'), + ('\u{1e137}', '\u{1e13d}'), + ('\u{1e14e}', '\u{1e14e}'), + ('\u{1e2c0}', '\u{1e2eb}'), + ('\u{1e800}', '\u{1e8c4}'), + ('\u{1e900}', '\u{1e943}'), + ('\u{1e94b}', '\u{1e94b}'), + ('\u{1ee00}', '\u{1ee03}'), + ('\u{1ee05}', '\u{1ee1f}'), + ('\u{1ee21}', '\u{1ee22}'), + ('\u{1ee24}', '\u{1ee24}'), + ('\u{1ee27}', '\u{1ee27}'), + ('\u{1ee29}', '\u{1ee32}'), + ('\u{1ee34}', '\u{1ee37}'), + ('\u{1ee39}', '\u{1ee39}'), + ('\u{1ee3b}', '\u{1ee3b}'), + ('\u{1ee42}', '\u{1ee42}'), + ('\u{1ee47}', '\u{1ee47}'), + ('\u{1ee49}', '\u{1ee49}'), + ('\u{1ee4b}', '\u{1ee4b}'), + ('\u{1ee4d}', '\u{1ee4f}'), + ('\u{1ee51}', '\u{1ee52}'), + ('\u{1ee54}', '\u{1ee54}'), + ('\u{1ee57}', '\u{1ee57}'), + ('\u{1ee59}', '\u{1ee59}'), + ('\u{1ee5b}', '\u{1ee5b}'), + ('\u{1ee5d}', '\u{1ee5d}'), + ('\u{1ee5f}', '\u{1ee5f}'), + ('\u{1ee61}', '\u{1ee62}'), + ('\u{1ee64}', '\u{1ee64}'), + ('\u{1ee67}', '\u{1ee6a}'), + ('\u{1ee6c}', '\u{1ee72}'), + ('\u{1ee74}', '\u{1ee77}'), + ('\u{1ee79}', '\u{1ee7c}'), + ('\u{1ee7e}', '\u{1ee7e}'), + ('\u{1ee80}', '\u{1ee89}'), + ('\u{1ee8b}', '\u{1ee9b}'), + ('\u{1eea1}', '\u{1eea3}'), + ('\u{1eea5}', '\u{1eea9}'), + ('\u{1eeab}', '\u{1eebb}'), + ('\u{20000}', '\u{2a6dd}'), + ('\u{2a700}', '\u{2b734}'), + ('\u{2b740}', '\u{2b81d}'), + ('\u{2b820}', '\u{2cea1}'), + ('\u{2ceb0}', '\u{2ebe0}'), + ('\u{2f800}', '\u{2fa1d}'), + ('\u{30000}', '\u{3134a}'), + ]; + + pub fn XID_Start(c: char) -> bool { + super::bsearch_range_table(c, XID_Start_table) + } +} +
pub const UNICODE_VERSION: (u64, u64, u64);
The version of Unicode +that this version of unicode-xid is based on.
+Determine if a char
is a valid identifier for a parser and/or lexer according to
+Unicode Standard Annex #31 rules.
+extern crate unicode_xid; + +use unicode_xid::UnicodeXID; + +fn main() { + let ch = 'a'; + println!("Is {} a valid start of an identifier? {}", ch, UnicodeXID::is_xid_start(ch)); +}
unicode-xid supports a no_std
feature. This eliminates dependence
+on std, and instead uses equivalent functions from core.
UNICODE_VERSION | The version of Unicode +that this version of unicode-xid is based on. + |
UnicodeXID | Methods for determining if a character is a valid identifier character. + |
Redirecting to ../../unicode_xid/constant.UNICODE_VERSION.html...
+ + + \ No newline at end of file diff --git a/static/api-docs/m_captcha/0.1.3/unicode_xid/trait.UnicodeXID.html b/static/api-docs/m_captcha/0.1.3/unicode_xid/trait.UnicodeXID.html new file mode 100644 index 0000000..096daf6 --- /dev/null +++ b/static/api-docs/m_captcha/0.1.3/unicode_xid/trait.UnicodeXID.html @@ -0,0 +1,16 @@ +Methods for determining if a character is a valid identifier character.
+fn is_xid_start(self) -> bool
[src]Returns whether the specified character satisfies the 'XID_Start' +Unicode property.
+'XID_Start' is a Unicode Derived Property specified in +UAX #31, +mostly similar to ID_Start but modified for closure under NFKx.
+fn is_xid_continue(self) -> bool
[src]Returns whether the specified char
satisfies the 'XID_Continue'
+Unicode property.
'XID_Continue' is a Unicode Derived Property specified in +UAX #31, +mostly similar to 'ID_Continue' but modified for closure under NFKx.
+impl UnicodeXID for char
[src]fn is_xid_start(self) -> bool
[src]fn is_xid_continue(self) -> bool
[src]