diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src')
23 files changed, 1700 insertions, 1124 deletions
| diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx b/packages/taler-wallet-webextension/src/NavigationBar.tsx index 56704fb57..8dc73efdb 100644 --- a/packages/taler-wallet-webextension/src/NavigationBar.tsx +++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx @@ -42,6 +42,7 @@ export enum Pages {    transaction = "/transaction/:tid",    provider_detail = "/provider/:pid",    provider_add = "/provider/add", +  exchange_add = "/exchange/add",    reset_required = "/reset-required",    payback = "/payback", diff --git a/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx b/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx index 3b9519f39..c22103a85 100644 --- a/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx +++ b/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx @@ -48,8 +48,8 @@ export function CheckboxOutlined({    label,  }: Props): VNode {    return ( -    <Outlined> -      <StyledCheckboxLabel onClick={onToggle}> +    <StyledCheckboxLabel onClick={onToggle}> +      <Outlined>          <span>            <input              type="checkbox" @@ -62,7 +62,7 @@ export function CheckboxOutlined({            </div>            <label for={name}>{label}</label>          </span> -      </StyledCheckboxLabel> -    </Outlined> +      </Outlined> +    </StyledCheckboxLabel>    );  } diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx b/packages/taler-wallet-webextension/src/components/styled/index.tsx index b2ca13801..7cef8789b 100644 --- a/packages/taler-wallet-webextension/src/components/styled/index.tsx +++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx @@ -476,6 +476,14 @@ const ButtonVariant = styled(Button)`    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);  `; +export const LinkDestructive = styled(Link)` +  background-color: rgb(202, 60, 60); +`; + +export const LinkPrimary = styled(Link)` +  color: rgb(66, 184, 221); +`; +  export const ButtonPrimary = styled(ButtonVariant)<{ small?: boolean }>`    font-size: ${({ small }) => (small ? "small" : "inherit")};    background-color: rgb(66, 184, 221); @@ -892,12 +900,14 @@ export const StyledCheckboxLabel = styled.div`    text-transform: uppercase;    /* font-weight: bold; */    text-align: center; +  cursor: pointer;    span {      input {        display: none;        opacity: 0;        width: 1em;        height: 1em; +      cursor: pointer;      }      div {        display: inline-grid; @@ -916,6 +926,7 @@ export const StyledCheckboxLabel = styled.div`      label {        padding: 0px;        font-size: small; +      cursor: pointer;      }    } diff --git a/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx b/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx new file mode 100644 index 000000000..5eddde64f --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx @@ -0,0 +1,129 @@ +import { i18n } from "@gnu-taler/taler-util"; +import { Fragment, h, VNode } from "preact"; +import { CheckboxOutlined } from "../components/CheckboxOutlined"; +import { ExchangeXmlTos } from "../components/ExchangeToS"; +import { +  ButtonSuccess, +  ButtonWarning, +  LinkSuccess, +  TermsOfService, +  WarningBox, +} from "../components/styled"; +import { TermsState } from "../utils"; + +interface Props { +  reviewing: boolean; +  reviewed: boolean; +  terms: TermsState; +  onReview?: (b: boolean) => void; +  onAccept: (b: boolean) => void; +} +export function TermsOfServiceSection({ +  reviewed, +  reviewing, +  terms, +  onAccept, +  onReview, +}: Props): VNode { +  if (!reviewing) { +    if (!reviewed) { +      if (!onReview) { +        return <section>Terms of service status: {terms.status}</section>; +      } +      return ( +        <Fragment> +          {terms.status === "new" && ( +            <section> +              <ButtonSuccess upperCased onClick={() => onReview(true)}> +                {i18n.str`Review exchange terms of service`} +              </ButtonSuccess> +            </section> +          )} +          {terms.status === "changed" && ( +            <section> +              <ButtonWarning upperCased onClick={() => onReview(true)}> +                {i18n.str`Review new version of terms of service`} +              </ButtonWarning> +            </section> +          )} +        </Fragment> +      ); +    } +    return ( +      <Fragment> +        {onReview && ( +          <section> +            <LinkSuccess upperCased onClick={() => onReview(true)}> +              {i18n.str`Show terms of service`} +            </LinkSuccess> +          </section> +        )} +        <section> +          <CheckboxOutlined +            name="terms" +            enabled={reviewed} +            label={i18n.str`I accept the exchange terms of service`} +            onToggle={() => { +              console.log("asdasd", reviewed); +              onAccept(!reviewed); +              if (onReview) onReview(false); +            }} +          /> +        </section> +      </Fragment> +    ); +  } +  return ( +    <Fragment> +      {terms.status !== "notfound" && !terms.content && ( +        <section> +          <WarningBox> +            The exchange reply with a empty terms of service +          </WarningBox> +        </section> +      )} +      {terms.status !== "accepted" && terms.content && ( +        <section> +          {terms.content.type === "xml" && ( +            <TermsOfService> +              <ExchangeXmlTos doc={terms.content.document} /> +            </TermsOfService> +          )} +          {terms.content.type === "plain" && ( +            <div style={{ textAlign: "left" }}> +              <pre>{terms.content.content}</pre> +            </div> +          )} +          {terms.content.type === "html" && ( +            <iframe src={terms.content.href.toString()} /> +          )} +          {terms.content.type === "pdf" && ( +            <a href={terms.content.location.toString()} download="tos.pdf"> +              Download Terms of Service +            </a> +          )} +        </section> +      )} +      {reviewed && onReview && ( +        <section> +          <LinkSuccess upperCased onClick={() => onReview(false)}> +            {i18n.str`Hide terms of service`} +          </LinkSuccess> +        </section> +      )} +      {terms.status !== "notfound" && ( +        <section> +          <CheckboxOutlined +            name="terms" +            enabled={reviewed} +            label={i18n.str`I accept the exchange terms of service`} +            onToggle={() => { +              onAccept(!reviewed); +              if (onReview) onReview(false); +            }} +          /> +        </section> +      )} +    </Fragment> +  ); +} diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx index 54ae19c61..fbbecd6f3 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx @@ -21,6 +21,7 @@  import { amountFractionalBase } from "@gnu-taler/taler-util";  import { createExample } from "../test-utils"; +import { termsHtml, termsPdf, termsPlain, termsXml } from "./termsExample";  import { View as TestedComponent } from "./Withdraw";  export default { @@ -31,751 +32,6 @@ export default {    },  }; -const termsHtml = `<html xmlns="http://www.w3.org/1999/xhtml" lang="en"> -<head> -  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> -  <title>Terms Of Service — Taler Terms of Service</title> -</head><body> -  <div> -    Terms of service -  </div> -  <div> -    A complete separated html with it's own design -  </div> -</body> -</html> -`; -const termsPlain = ` -Terms Of Service -**************** - -Last Updated: 12.4.2019 - -Welcome! Taler Systems SA (“we,” “our,” or “us”) provides a payment -service through our Internet presence (collectively the “Services”). -Before using our Services, please read the Terms of Service (the -“Terms” or the “Agreement”) carefully. - - -Overview -======== - -This section provides a brief summary of the highlights of this -Agreement. Please note that when you accept this Agreement, you are -accepting all of the terms and conditions and not just this section. -We and possibly other third parties provide Internet services which -interact with the Taler Wallet’s self-hosted personal payment -application. When using the Taler Wallet to interact with our -Services, you are agreeing to our Terms, so please read carefully. - - -Highlights: ------------ - -   * You are responsible for keeping the data in your Taler Wallet at -     all times under your control. Any losses arising from you not -     being in control of your private information are your problem. - -   * We will try to transfer funds we hold in escrow for our users to -     any legal recipient to the best of our ability within the -     limitations of the law and our implementation. However, the -     Services offered today are highly experimental and the set of -     recipients of funds is severely restricted. - -   * For our Services, we may charge transaction fees. The specific -     fee structure is provided based on the Taler protocol and should -     be shown to you when you withdraw electronic coins using a Taler -     Wallet. You agree and understand that the Taler protocol allows -     for the fee structure to change. - -   * You agree to not intentionally overwhelm our systems with -     requests and follow responsible disclosure if you find security -     issues in our services. - -   * We cannot be held accountable for our Services not being -     available due to circumstances beyond our control. If we modify -     or terminate our services, we will try to give you the -     opportunity to recover your funds. However, given the -     experimental state of the Services today, this may not be -     possible. You are strongly advised to limit your use of the -     Service to small-scale experiments expecting total loss of all -     funds. - -These terms outline approved uses of our Services. The Services and -these Terms are still at an experimental stage. If you have any -questions or comments related to this Agreement, please send us a -message to legal@taler-systems.com. If you do not agree to this -Agreement, you must not use our Services. - - -How you accept this policy -========================== - -By sending funds to us (to top-up your Taler Wallet), you acknowledge -that you have read, understood, and agreed to these Terms. We reserve -the right to change these Terms at any time. If you disagree with the -change, we may in the future offer you with an easy option to recover -your unspent funds. However, in the current experimental period you -acknowledge that this feature is not yet available, resulting in your -funds being lost unless you accept the new Terms. If you continue to -use our Services other than to recover your unspent funds, your -continued use of our Services following any such change will signify -your acceptance to be bound by the then current Terms. Please check -the effective date above to determine if there have been any changes -since you have last reviewed these Terms. - - -Services -======== - -We will try to transfer funds that we hold in escrow for our users to -any legal recipient to the best of our ability and within the -limitations of the law and our implementation. However, the Services -offered today are highly experimental and the set of recipients of -funds is severely restricted.  The Taler Wallet can be loaded by -exchanging fiat currencies against electronic coins. We are providing -this exchange service. Once your Taler Wallet is loaded with -electronic coins they can be spent for purchases if the seller is -accepting Taler as a means of payment. We are not guaranteeing that -any seller is accepting Taler at all or a particular seller.  The -seller or recipient of deposits of electronic coins must specify the -target account, as per the design of the Taler protocol. They are -responsible for following the protocol and specifying the correct bank -account, and are solely liable for any losses that may arise from -specifying the wrong account. We will allow the government to link -wire transfers to the underlying contract hash. It is the -responsibility of recipients to preserve the full contracts and to pay -whatever taxes and charges may be applicable. Technical issues may -lead to situations where we are unable to make transfers at all or -lead to incorrect transfers that cannot be reversed. We will only -refuse to execute transfers if the transfers are prohibited by a -competent legal authority and we are ordered to do so. - - -Fees -==== - -You agree to pay the fees for exchanges and withdrawals completed via -the Taler Wallet ("Fees") as defined by us, which we may change from -time to time. With the exception of wire transfer fees, Taler -transaction fees are set for any electronic coin at the time of -withdrawal and fixed throughout the validity period of the respective -electronic coin. Your wallet should obtain and display applicable fees -when withdrawing funds. Fees for coins obtained as change may differ -from the fees applicable to the original coin. Wire transfer fees that -are independent from electronic coins may change annually.  You -authorize us to charge or deduct applicable fees owed in connection -with deposits, exchanges and withdrawals following the rules of the -Taler protocol. We reserve the right to provide different types of -rewards to users either in the form of discount for our Services or in -any other form at our discretion and without prior notice to you. - - -Eligibility -=========== - -To be eligible to use our Services, you must be able to form legally -binding contracts or have the permission of your legal guardian. By -using our Services, you represent and warrant that you meet all -eligibility requirements that we outline in these Terms. - - -Financial self-responsibility -============================= - -You will be responsible for maintaining the availability, integrity -and confidentiality of the data stored in your wallet. When you setup -a Taler Wallet, you are strongly advised to follow the precautionary -measures offered by the software to minimize the chances to losse -access to or control over your Wallet data. We will not be liable for -any loss or damage arising from your failure to comply with this -paragraph. - - -Copyrights and trademarks -========================= - -The Taler Wallet is released under the terms of the GNU General Public -License (GNU GPL). You have the right to access, use, and share the -Taler Wallet, in modified or unmodified form. However, the GPL is a -strong copyleft license, which means that any derivative works must be -distributed under the same license terms as the original software. If -you have any questions, you should review the GNU GPL’s full terms and -conditions at https://www.gnu.org/licenses/gpl-3.0.en.html.  “Taler” -itself is a trademark of Taler Systems SA. You are welcome to use the -name in relation to processing payments using the Taler protocol, -assuming your use is compatible with an official release from the GNU -Project that is not older than two years. - - -Your use of our services -======================== - -When using our Services, you agree to not take any action that -intentionally imposes an unreasonable load on our infrastructure. If -you find security problems in our Services, you agree to first report -them to security@taler-systems.com and grant us the right to publish -your report. We warrant that we will ourselves publicly disclose any -issues reported within 3 months, and that we will not prosecute anyone -reporting security issues if they did not exploit the issue beyond a -proof-of-concept, and followed the above responsible disclosure -practice. - - -Limitation of liability & disclaimer of warranties -================================================== - -You understand and agree that we have no control over, and no duty to -take any action regarding: Failures, disruptions, errors, or delays in -processing that you may experience while using our Services; The risk -of failure of hardware, software, and Internet connections; The risk -of malicious software being introduced or found in the software -underlying the Taler Wallet; The risk that third parties may obtain -unauthorized access to information stored within your Taler Wallet, -including, but not limited to your Taler Wallet coins or backup -encryption keys.  You release us from all liability related to any -losses, damages, or claims arising from: - -1. user error such as forgotten passwords, incorrectly constructed -   transactions; - -2. server failure or data loss; - -3. unauthorized access to the Taler Wallet application; - -4. bugs or other errors in the Taler Wallet software; and - -5. any unauthorized third party activities, including, but not limited -   to, the use of viruses, phishing, brute forcing, or other means of -   attack against the Taler Wallet. We make no representations -   concerning any Third Party Content contained in or accessed through -   our Services. - -Any other terms, conditions, warranties, or representations associated -with such content, are solely between you and such organizations -and/or individuals. - - -Limitation of liability -======================= - -To the fullest extent permitted by applicable law, in no event will we -or any of our officers, directors, representatives, agents, servants, -counsel, employees, consultants, lawyers, and other personnel -authorized to act, acting, or purporting to act on our behalf -(collectively the “Taler Parties”) be liable to you under contract, -tort, strict liability, negligence, or any other legal or equitable -theory, for: - -1. any lost profits, data loss, cost of procurement of substitute -   goods or services, or direct, indirect, incidental, special, -   punitive, compensatory, or consequential damages of any kind -   whatsoever resulting from: - -   1. your use of, or conduct in connection with, our services; - -   2. any unauthorized use of your wallet and/or private key due to -      your failure to maintain the confidentiality of your wallet; - -   3. any interruption or cessation of transmission to or from the -      services; or - -   4. any bugs, viruses, trojan horses, or the like that are found in -      the Taler Wallet software or that may be transmitted to or -      through our services by any third party (regardless of the -      source of origination), or - -2. any direct damages. - -These limitations apply regardless of legal theory, whether based on -tort, strict liability, breach of contract, breach of warranty, or any -other legal theory, and whether or not we were advised of the -possibility of such damages. Some jurisdictions do not allow the -exclusion or limitation of liability for consequential or incidental -damages, so the above limitation may not apply to you. - - -Warranty disclaimer -=================== - -Our services are provided "as is" and without warranty of any kind. To -the maximum extent permitted by law, we disclaim all representations -and warranties, express or implied, relating to the services and -underlying software or any content on the services, whether provided -or owned by us or by any third party, including without limitation, -warranties of merchantability, fitness for a particular purpose, -title, non-infringement, freedom from computer virus, and any implied -warranties arising from course of dealing, course of performance, or -usage in trade, all of which are expressly disclaimed. In addition, we -do not represent or warrant that the content accessible via the -services is accurate, complete, available, current, free of viruses or -other harmful components, or that the results of using the services -will meet your requirements. Some states do not allow the disclaimer -of implied warranties, so the foregoing disclaimers may not apply to -you. This paragraph gives you specific legal rights and you may also -have other legal rights that vary from state to state. - - -Indemnity -========= - -To the extent permitted by applicable law, you agree to defend, -indemnify, and hold harmless the Taler Parties from and against any -and all claims, damages, obligations, losses, liabilities, costs or -debt, and expenses (including, but not limited to, attorney’s fees) -arising from: (a) your use of and access to the Services; (b) any -feedback or submissions you provide to us concerning the Taler Wallet; -(c) your violation of any term of this Agreement; or (d) your -violation of any law, rule, or regulation, or the rights of any third -party. - - -Time limitation on claims -========================= - -You agree that any claim you may have arising out of or related to -your relationship with us must be filed within one year after such -claim arises, otherwise, your claim in permanently barred. - - -Governing law -============= - -No matter where you’re located, the laws of Switzerland will govern -these Terms. If any provisions of these Terms are inconsistent with -any applicable law, those provisions will be superseded or modified -only to the extent such provisions are inconsistent. The parties agree -to submit to the ordinary courts in Zurich, Switzerland for exclusive -jurisdiction of any dispute arising out of or related to your use of -the Services or your breach of these Terms. - - -Termination -=========== - -In the event of termination concerning your use of our Services, your -obligations under this Agreement will still continue. - - -Discontinuance of services -========================== - -We may, in our sole discretion and without cost to you, with or -without prior notice, and at any time, modify or discontinue, -temporarily or permanently, any portion of our Services. We will use -the Taler protocol’s provisions to notify Wallets if our Services are -to be discontinued. It is your responsibility to ensure that the Taler -Wallet is online at least once every three months to observe these -notifications. We shall not be held responsible or liable for any loss -of funds in the event that we discontinue or depreciate the Services -and your Taler Wallet fails to transfer out the coins within a three -months notification period. - - -No waiver -========= - -Our failure to exercise or delay in exercising any right, power, or -privilege under this Agreement shall not operate as a waiver; nor -shall any single or partial exercise of any right, power, or privilege -preclude any other or further exercise thereof. - - -Severability -============ - -If it turns out that any part of this Agreement is invalid, void, or -for any reason unenforceable, that term will be deemed severable and -limited or eliminated to the minimum extent necessary. - - -Force majeure -============= - -We shall not be held liable for any delays, failure in performance, or -interruptions of service which result directly or indirectly from any -cause or condition beyond our reasonable control, including but not -limited to: any delay or failure due to any act of God, act of civil -or military authorities, act of terrorism, civil disturbance, war, -strike or other labor dispute, fire, interruption in -telecommunications or Internet services or network provider services, -failure of equipment and/or software, other catastrophe, or any other -occurrence which is beyond our reasonable control and shall not affect -the validity and enforceability of any remaining provisions. - - -Assignment -========== - -You agree that we may assign any of our rights and/or transfer, sub- -contract, or delegate any of our obligations under these Terms. - - -Entire agreement -================ - -This Agreement sets forth the entire understanding and agreement as to -the subject matter hereof and supersedes any and all prior -discussions, agreements, and understandings of any kind (including, -without limitation, any prior versions of this Agreement) and every -nature between us. Except as provided for above, any modification to -this Agreement must be in writing and must be signed by both parties. - - -Questions or comments -===================== - -We welcome comments, questions, concerns, or suggestions. Please send -us a message on our contact page at legal@taler-systems.com. - -`; - -const termsXml = `<?xml version="1.0" encoding="utf-8"?> -<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd"> -<!-- Generated by Docutils 0.14 --> -<document source="/home/grothoff/research/taler/exchange/contrib/tos/tos.rst"> -    <section ids="terms-of-service" names="terms\ of\ service"> -        <title>Terms Of Service</title> -        <paragraph>Last Updated: 12.4.2019</paragraph> -        <paragraph>Welcome! Taler Systems SA (“we,” “our,” or “us”) provides a payment service -            through our Internet presence (collectively the “Services”). Before using our -            Services, please read the Terms of Service (the “Terms” or the “Agreement”) -            carefully.</paragraph> -        <section ids="overview" names="overview"> -            <title>Overview</title> -            <paragraph>This section provides a brief summary of the highlights of this -                Agreement. Please note that when you accept this Agreement, you are accepting -                all of the terms and conditions and not just this section. We and possibly -                other third parties provide Internet services which interact with the Taler -                Wallet’s self-hosted personal payment application. When using the Taler Wallet -                to interact with our Services, you are agreeing to our Terms, so please read -                carefully.</paragraph> -            <section ids="highlights" names="highlights:"> -                <title>Highlights:</title> -                <block_quote> -                    <bullet_list bullet="•"> -                        <list_item> -                            <paragraph>You are responsible for keeping the data in your Taler Wallet at all times -                                under your control. Any losses arising from you not being in control of -                                your private information are your problem.</paragraph> -                        </list_item> -                        <list_item> -                            <paragraph>We will try to transfer funds we hold in escrow for our users to any legal -                                recipient to the best of our ability within the limitations of the law and -                                our implementation. However, the Services offered today are highly -                                experimental and the set of recipients of funds is severely restricted.</paragraph> -                        </list_item> -                        <list_item> -                            <paragraph>For our Services, we may charge transaction fees. The specific fee structure -                                is provided based on the Taler protocol and should be shown to you when you -                                withdraw electronic coins using a Taler Wallet. You agree and understand -                                that the Taler protocol allows for the fee structure to change.</paragraph> -                        </list_item> -                        <list_item> -                            <paragraph>You agree to not intentionally overwhelm our systems with requests and -                                follow responsible disclosure if you find security issues in our services.</paragraph> -                        </list_item> -                        <list_item> -                            <paragraph>We cannot be held accountable for our Services not being available due to -                                circumstances beyond our control. If we modify or terminate our services, -                                we will try to give you the opportunity to recover your funds. However, -                                given the experimental state of the Services today, this may not be -                                possible. You are strongly advised to limit your use of the Service -                                to small-scale experiments expecting total loss of all funds.</paragraph> -                        </list_item> -                    </bullet_list> -                </block_quote> -                <paragraph>These terms outline approved uses of our Services. The Services and these -                    Terms are still at an experimental stage. If you have any questions or -                    comments related to this Agreement, please send us a message to -                    <reference refuri="mailto:legal@taler-systems.com">legal@taler-systems.com</reference>. If you do not agree to this Agreement, you must not -                    use our Services.</paragraph> -            </section> -        </section> -        <section ids="how-you-accept-this-policy" names="how\ you\ accept\ this\ policy"> -            <title>How you accept this policy</title> -            <paragraph>By sending funds to us (to top-up your Taler Wallet), you acknowledge that you -                have read, understood, and agreed to these Terms. We reserve the right to -                change these Terms at any time. If you disagree with the change, we may in the -                future offer you with an easy option to recover your unspent funds. However, -                in the current experimental period you acknowledge that this feature is not -                yet available, resulting in your funds being lost unless you accept the new -                Terms. If you continue to use our Services other than to recover your unspent -                funds, your continued use of our Services following any such change will -                signify your acceptance to be bound by the then current Terms. Please check -                the effective date above to determine if there have been any changes since you -                have last reviewed these Terms.</paragraph> -        </section> -        <section ids="services" names="services"> -            <title>Services</title> -            <paragraph>We will try to transfer funds that we hold in escrow for our users to any -                legal recipient to the best of our ability and within the limitations of the -                law and our implementation. However, the Services offered today are highly -                experimental and the set of recipients of funds is severely restricted.  The -                Taler Wallet can be loaded by exchanging fiat currencies against electronic -                coins. We are providing this exchange service. Once your Taler Wallet is -                loaded with electronic coins they can be spent for purchases if the seller is -                accepting Taler as a means of payment. We are not guaranteeing that any seller -                is accepting Taler at all or a particular seller.  The seller or recipient of -                deposits of electronic coins must specify the target account, as per the -                design of the Taler protocol. They are responsible for following the protocol -                and specifying the correct bank account, and are solely liable for any losses -                that may arise from specifying the wrong account. We will allow the government -                to link wire transfers to the underlying contract hash. It is the -                responsibility of recipients to preserve the full contracts and to pay -                whatever taxes and charges may be applicable. Technical issues may lead to -                situations where we are unable to make transfers at all or lead to incorrect -                transfers that cannot be reversed. We will only refuse to execute transfers if -                the transfers are prohibited by a competent legal authority and we are ordered -                to do so.</paragraph> -        </section> -        <section ids="fees" names="fees"> -            <title>Fees</title> -            <paragraph>You agree to pay the fees for exchanges and withdrawals completed via the -                Taler Wallet (“Fees”) as defined by us, which we may change from time to -                time. With the exception of wire transfer fees, Taler transaction fees are set -                for any electronic coin at the time of withdrawal and fixed throughout the -                validity period of the respective electronic coin. Your wallet should obtain -                and display applicable fees when withdrawing funds. Fees for coins obtained as -                change may differ from the fees applicable to the original coin. Wire transfer -                fees that are independent from electronic coins may change annually.  You -                authorize us to charge or deduct applicable fees owed in connection with -                deposits, exchanges and withdrawals following the rules of the Taler protocol. -                We reserve the right to provide different types of rewards to users either in -                the form of discount for our Services or in any other form at our discretion -                and without prior notice to you.</paragraph> -        </section> -        <section ids="eligibility" names="eligibility"> -            <title>Eligibility</title> -            <paragraph>To be eligible to use our Services, you must be able to form legally binding -                contracts or have the permission of your legal guardian. By using our -                Services, you represent and warrant that you meet all eligibility requirements -                that we outline in these Terms.</paragraph> -        </section> -        <section ids="financial-self-responsibility" names="financial\ self-responsibility"> -            <title>Financial self-responsibility</title> -            <paragraph>You will be responsible for maintaining the availability, integrity and -                confidentiality of the data stored in your wallet. When you setup a Taler -                Wallet, you are strongly advised to follow the precautionary measures offered -                by the software to minimize the chances to losse access to or control over -                your Wallet data. We will not be liable for any loss or damage arising from -                your failure to comply with this paragraph.</paragraph> -        </section> -        <section ids="copyrights-and-trademarks" names="copyrights\ and\ trademarks"> -            <title>Copyrights and trademarks</title> -            <paragraph>The Taler Wallet is released under the terms of the GNU General Public License -                (GNU GPL). You have the right to access, use, and share the Taler Wallet, in -                modified or unmodified form. However, the GPL is a strong copyleft license, -                which means that any derivative works must be distributed under the same -                license terms as the original software. If you have any questions, you should -                review the GNU GPL’s full terms and conditions at -                <reference refuri="https://www.gnu.org/licenses/gpl-3.0.en.html">https://www.gnu.org/licenses/gpl-3.0.en.html</reference>.  “Taler” itself is a trademark -                of Taler Systems SA. You are welcome to use the name in relation to processing -                payments using the Taler protocol, assuming your use is compatible with an -                official release from the GNU Project that is not older than two years.</paragraph> -        </section> -        <section ids="your-use-of-our-services" names="your\ use\ of\ our\ services"> -            <title>Your use of our services</title> -            <paragraph>When using our Services, you agree to not take any action that intentionally -                imposes an unreasonable load on our infrastructure. If you find security -                problems in our Services, you agree to first report them to -                <reference refuri="mailto:security@taler-systems.com">security@taler-systems.com</reference> and grant us the right to publish your report. We -                warrant that we will ourselves publicly disclose any issues reported within 3 -                months, and that we will not prosecute anyone reporting security issues if -                they did not exploit the issue beyond a proof-of-concept, and followed the -                above responsible disclosure practice.</paragraph> -        </section> -        <section ids="limitation-of-liability-disclaimer-of-warranties" names="limitation\ of\ liability\ &\ disclaimer\ of\ warranties"> -            <title>Limitation of liability & disclaimer of warranties</title> -            <paragraph>You understand and agree that we have no control over, and no duty to take any -                action regarding: Failures, disruptions, errors, or delays in processing that -                you may experience while using our Services; The risk of failure of hardware, -                software, and Internet connections; The risk of malicious software being -                introduced or found in the software underlying the Taler Wallet; The risk that -                third parties may obtain unauthorized access to information stored within your -                Taler Wallet, including, but not limited to your Taler Wallet coins or backup -                encryption keys.  You release us from all liability related to any losses, -                damages, or claims arising from:</paragraph> -            <enumerated_list enumtype="loweralpha" prefix="(" suffix=")"> -                <list_item> -                    <paragraph>user error such as forgotten passwords, incorrectly constructed -                        transactions;</paragraph> -                </list_item> -                <list_item> -                    <paragraph>server failure or data loss;</paragraph> -                </list_item> -                <list_item> -                    <paragraph>unauthorized access to the Taler Wallet application;</paragraph> -                </list_item> -                <list_item> -                    <paragraph>bugs or other errors in the Taler Wallet software; and</paragraph> -                </list_item> -                <list_item> -                    <paragraph>any unauthorized third party activities, including, but not limited to, -                        the use of viruses, phishing, brute forcing, or other means of attack -                        against the Taler Wallet. We make no representations concerning any -                        Third Party Content contained in or accessed through our Services.</paragraph> -                </list_item> -            </enumerated_list> -            <paragraph>Any other terms, conditions, warranties, or representations associated with -                such content, are solely between you and such organizations and/or -                individuals.</paragraph> -        </section> -        <section ids="limitation-of-liability" names="limitation\ of\ liability"> -            <title>Limitation of liability</title> -            <paragraph>To the fullest extent permitted by applicable law, in no event will we or any -                of our officers, directors, representatives, agents, servants, counsel, -                employees, consultants, lawyers, and other personnel authorized to act, -                acting, or purporting to act on our behalf (collectively the “Taler Parties”) -                be liable to you under contract, tort, strict liability, negligence, or any -                other legal or equitable theory, for:</paragraph> -            <enumerated_list enumtype="loweralpha" prefix="(" suffix=")"> -                <list_item> -                    <paragraph>any lost profits, data loss, cost of procurement of substitute goods or -                        services, or direct, indirect, incidental, special, punitive, compensatory, -                        or consequential damages of any kind whatsoever resulting from:</paragraph> -                </list_item> -            </enumerated_list> -            <block_quote> -                <enumerated_list enumtype="lowerroman" prefix="(" suffix=")"> -                    <list_item> -                        <paragraph>your use of, or conduct in connection with, our services;</paragraph> -                    </list_item> -                    <list_item> -                        <paragraph>any unauthorized use of your wallet and/or private key due to your -                            failure to maintain the confidentiality of your wallet;</paragraph> -                    </list_item> -                    <list_item> -                        <paragraph>any interruption or cessation of transmission to or from the services; or</paragraph> -                    </list_item> -                    <list_item> -                        <paragraph>any bugs, viruses, trojan horses, or the like that are found in the Taler -                            Wallet software or that may be transmitted to or through our services by -                            any third party (regardless of the source of origination), or</paragraph> -                    </list_item> -                </enumerated_list> -            </block_quote> -            <enumerated_list enumtype="loweralpha" prefix="(" start="2" suffix=")"> -                <list_item> -                    <paragraph>any direct damages.</paragraph> -                </list_item> -            </enumerated_list> -            <paragraph>These limitations apply regardless of legal theory, whether based on tort, -                strict liability, breach of contract, breach of warranty, or any other legal -                theory, and whether or not we were advised of the possibility of such -                damages. Some jurisdictions do not allow the exclusion or limitation of -                liability for consequential or incidental damages, so the above limitation may -                not apply to you.</paragraph> -        </section> -        <section ids="warranty-disclaimer" names="warranty\ disclaimer"> -            <title>Warranty disclaimer</title> -            <paragraph>Our services are provided “as is” and without warranty of any kind. To the -                maximum extent permitted by law, we disclaim all representations and -                warranties, express or implied, relating to the services and underlying -                software or any content on the services, whether provided or owned by us or by -                any third party, including without limitation, warranties of merchantability, -                fitness for a particular purpose, title, non-infringement, freedom from -                computer virus, and any implied warranties arising from course of dealing, -                course of performance, or usage in trade, all of which are expressly -                disclaimed. In addition, we do not represent or warrant that the content -                accessible via the services is accurate, complete, available, current, free of -                viruses or other harmful components, or that the results of using the services -                will meet your requirements. Some states do not allow the disclaimer of -                implied warranties, so the foregoing disclaimers may not apply to you. This -                paragraph gives you specific legal rights and you may also have other legal -                rights that vary from state to state.</paragraph> -        </section> -        <section ids="indemnity" names="indemnity"> -            <title>Indemnity</title> -            <paragraph>To the extent permitted by applicable law, you agree to defend, indemnify, and -                hold harmless the Taler Parties from and against any and all claims, damages, -                obligations, losses, liabilities, costs or debt, and expenses (including, but -                not limited to, attorney’s fees) arising from: (a) your use of and access to -                the Services; (b) any feedback or submissions you provide to us concerning the -                Taler Wallet; (c) your violation of any term of this Agreement; or (d) your -                violation of any law, rule, or regulation, or the rights of any third party.</paragraph> -        </section> -        <section ids="time-limitation-on-claims" names="time\ limitation\ on\ claims"> -            <title>Time limitation on claims</title> -            <paragraph>You agree that any claim you may have arising out of or related to your -                relationship with us must be filed within one year after such claim arises, -                otherwise, your claim in permanently barred.</paragraph> -        </section> -        <section ids="governing-law" names="governing\ law"> -            <title>Governing law</title> -            <paragraph>No matter where you’re located, the laws of Switzerland will govern these -                Terms. If any provisions of these Terms are inconsistent with any applicable -                law, those provisions will be superseded or modified only to the extent such -                provisions are inconsistent. The parties agree to submit to the ordinary -                courts in Zurich, Switzerland for exclusive jurisdiction of any dispute -                arising out of or related to your use of the Services or your breach of these -                Terms.</paragraph> -        </section> -        <section ids="termination" names="termination"> -            <title>Termination</title> -            <paragraph>In the event of termination concerning your use of our Services, your -                obligations under this Agreement will still continue.</paragraph> -        </section> -        <section ids="discontinuance-of-services" names="discontinuance\ of\ services"> -            <title>Discontinuance of services</title> -            <paragraph>We may, in our sole discretion and without cost to you, with or without prior -                notice, and at any time, modify or discontinue, temporarily or permanently, -                any portion of our Services. We will use the Taler protocol’s provisions to -                notify Wallets if our Services are to be discontinued. It is your -                responsibility to ensure that the Taler Wallet is online at least once every -                three months to observe these notifications. We shall not be held responsible -                or liable for any loss of funds in the event that we discontinue or depreciate -                the Services and your Taler Wallet fails to transfer out the coins within a -                three months notification period.</paragraph> -        </section> -        <section ids="no-waiver" names="no\ waiver"> -            <title>No waiver</title> -            <paragraph>Our failure to exercise or delay in exercising any right, power, or privilege -                under this Agreement shall not operate as a waiver; nor shall any single or -                partial exercise of any right, power, or privilege preclude any other or -                further exercise thereof.</paragraph> -        </section> -        <section ids="severability" names="severability"> -            <title>Severability</title> -            <paragraph>If it turns out that any part of this Agreement is invalid, void, or for any -                reason unenforceable, that term will be deemed severable and limited or -                eliminated to the minimum extent necessary.</paragraph> -        </section> -        <section ids="force-majeure" names="force\ majeure"> -            <title>Force majeure</title> -            <paragraph>We shall not be held liable for any delays, failure in performance, or -                interruptions of service which result directly or indirectly from any cause or -                condition beyond our reasonable control, including but not limited to: any -                delay or failure due to any act of God, act of civil or military authorities, -                act of terrorism, civil disturbance, war, strike or other labor dispute, fire, -                interruption in telecommunications or Internet services or network provider -                services, failure of equipment and/or software, other catastrophe, or any -                other occurrence which is beyond our reasonable control and shall not affect -                the validity and enforceability of any remaining provisions.</paragraph> -        </section> -        <section ids="assignment" names="assignment"> -            <title>Assignment</title> -            <paragraph>You agree that we may assign any of our rights and/or transfer, sub-contract, -                or delegate any of our obligations under these Terms.</paragraph> -        </section> -        <section ids="entire-agreement" names="entire\ agreement"> -            <title>Entire agreement</title> -            <paragraph>This Agreement sets forth the entire understanding and agreement as to the -                subject matter hereof and supersedes any and all prior discussions, -                agreements, and understandings of any kind (including, without limitation, any -                prior versions of this Agreement) and every nature between us. Except as -                provided for above, any modification to this Agreement must be in writing and -                must be signed by both parties.</paragraph> -        </section> -        <section ids="questions-or-comments" names="questions\ or\ comments"> -            <title>Questions or comments</title> -            <paragraph>We welcome comments, questions, concerns, or suggestions. Please send us a -                message on our contact page at <reference refuri="mailto:legal@taler-systems.com">legal@taler-systems.com</reference>.</paragraph> -        </section> -    </section> -</document> -`; -  export const NewTerms = createExample(TestedComponent, {    knownExchanges: [      { @@ -805,11 +61,12 @@ export const NewTerms = createExample(TestedComponent, {      null;    },    terms: { -    value: { +    content: {        type: "xml",        document: new DOMParser().parseFromString(termsXml, "text/xml"),      },      status: "new", +    version: "",    },  }); @@ -842,11 +99,12 @@ export const TermsReviewingPLAIN = createExample(TestedComponent, {      null;    },    terms: { -    value: { +    content: {        type: "plain",        content: termsPlain,      },      status: "new", +    version: "",    },    reviewing: true,  }); @@ -880,32 +138,18 @@ export const TermsReviewingHTML = createExample(TestedComponent, {      null;    },    terms: { -    value: { +    content: {        type: "html",        href: new URL(          `data:text/html;base64,${Buffer.from(termsHtml).toString("base64")}`,        ),      }, +    version: "",      status: "new",    },    reviewing: true,  }); -const termsPdf = ` -%PDF-1.2  -9 0 obj << >>  -stream -BT/ 9 Tf(This is the Exchange TERMS OF SERVICE)' ET -endstream -endobj -4 0 obj << /Type /Page /Parent 5 0 R /Contents 9 0 R >> endobj  -5 0 obj << /Kids [4 0 R ] /Count 1 /Type /Pages /MediaBox [ 0 0 180 20 ] >> endobj -3 0 obj << /Pages 5 0 R /Type /Catalog >> endobj -trailer -<< /Root 3 0 R >> -%%EOF -`; -  export const TermsReviewingPDF = createExample(TestedComponent, {    knownExchanges: [      { @@ -935,13 +179,14 @@ export const TermsReviewingPDF = createExample(TestedComponent, {      null;    },    terms: { -    value: { +    content: {        type: "pdf",        location: new URL(          `data:text/html;base64,${Buffer.from(termsPdf).toString("base64")}`,        ),      },      status: "new", +    version: "",    },    reviewing: true,  }); @@ -975,11 +220,12 @@ export const TermsReviewingXML = createExample(TestedComponent, {      null;    },    terms: { -    value: { +    content: {        type: "xml",        document: new DOMParser().parseFromString(termsXml, "text/xml"),      },      status: "new", +    version: "",    },    reviewing: true,  }); @@ -1012,11 +258,12 @@ export const NewTermsAccepted = createExample(TestedComponent, {      null;    },    terms: { -    value: { +    content: {        type: "xml",        document: new DOMParser().parseFromString(termsXml, "text/xml"),      },      status: "new", +    version: "",    },    reviewed: true,  }); @@ -1050,10 +297,11 @@ export const TermsShowAgainXML = createExample(TestedComponent, {      null;    },    terms: { -    value: { +    content: {        type: "xml",        document: new DOMParser().parseFromString(termsXml, "text/xml"),      }, +    version: "",      status: "new",    },    reviewed: true, @@ -1089,10 +337,11 @@ export const TermsChanged = createExample(TestedComponent, {      null;    },    terms: { -    value: { +    content: {        type: "xml",        document: new DOMParser().parseFromString(termsXml, "text/xml"),      }, +    version: "",      status: "changed",    },  }); @@ -1126,7 +375,9 @@ export const TermsNotFound = createExample(TestedComponent, {      null;    },    terms: { +    content: undefined,      status: "notfound", +    version: "",    },  }); @@ -1160,6 +411,8 @@ export const TermsAlreadyAccepted = createExample(TestedComponent, {    },    terms: {      status: "accepted", +    content: undefined, +    version: "",    },  }); @@ -1192,10 +445,11 @@ export const WithoutFee = createExample(TestedComponent, {      null;    },    terms: { -    value: { +    content: {        type: "xml",        document: new DOMParser().parseFromString(termsXml, "text/xml"),      },      status: "accepted", +    version: "",    },  }); diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx index 8258717bd..4ebbe11c6 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx +++ b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx @@ -25,14 +25,11 @@ import {    AmountJson,    Amounts,    ExchangeListItem, -  GetExchangeTosResult,    i18n,    WithdrawUriInfoResponse,  } from "@gnu-taler/taler-util"; -import { VNode, h, Fragment } from "preact"; +import { Fragment, h, VNode } from "preact";  import { useState } from "preact/hooks"; -import { CheckboxOutlined } from "../components/CheckboxOutlined"; -import { ExchangeXmlTos } from "../components/ExchangeToS";  import { LogoHeader } from "../components/LogoHeader";  import { Part } from "../components/Part";  import { SelectList } from "../components/SelectList"; @@ -40,19 +37,13 @@ import {    ButtonSuccess,    ButtonWarning,    LinkSuccess, -  TermsOfService,    WalletAction,    WarningText,  } from "../components/styled";  import { useAsyncAsHook } from "../hooks/useAsyncAsHook"; -import { -  acceptWithdrawal, -  getExchangeTos, -  getExchangeWithdrawalInfo, -  getWithdrawalDetailsForUri, -  listExchanges, -  setExchangeTosAccepted, -} from "../wxApi"; +import { amountToString, buildTermsOfServiceState, TermsState } from "../utils"; +import * as wxApi from "../wxApi"; +import { TermsOfServiceSection } from "./TermsOfServiceSection";  interface Props {    talerWithdrawUri?: string; @@ -60,7 +51,7 @@ interface Props {  export interface ViewProps {    withdrawalFee: AmountJson; -  exchangeBaseUrl: string; +  exchangeBaseUrl?: string;    amount: AmountJson;    onSwitchExchange: (ex: string) => void;    onWithdraw: () => Promise<void>; @@ -69,53 +60,10 @@ export interface ViewProps {    reviewing: boolean;    reviewed: boolean;    confirmed: boolean; -  terms: { -    value?: TermsDocument; -    status: TermsStatus; -  }; +  terms: TermsState;    knownExchanges: ExchangeListItem[];  } -type TermsStatus = "new" | "accepted" | "changed" | "notfound"; - -type TermsDocument = -  | TermsDocumentXml -  | TermsDocumentHtml -  | TermsDocumentPlain -  | TermsDocumentJson -  | TermsDocumentPdf; - -interface TermsDocumentXml { -  type: "xml"; -  document: Document; -} - -interface TermsDocumentHtml { -  type: "html"; -  href: URL; -} - -interface TermsDocumentPlain { -  type: "plain"; -  content: string; -} - -interface TermsDocumentJson { -  type: "json"; -  data: any; -} - -interface TermsDocumentPdf { -  type: "pdf"; -  location: URL; -} - -function amountToString(text: AmountJson): string { -  const aj = Amounts.jsonifyAmount(text); -  const amount = Amounts.stringifyValue(aj); -  return `${amount} ${aj.currency}`; -} -  export function View({    withdrawalFee,    exchangeBaseUrl, @@ -162,7 +110,9 @@ export function View({              kind="negative"            />          )} -        <Part title="Exchange" text={exchangeBaseUrl} kind="neutral" big /> +        {exchangeBaseUrl && ( +          <Part title="Exchange" text={exchangeBaseUrl} kind="neutral" big /> +        )}        </section>        {!reviewing && (          <section> @@ -190,13 +140,6 @@ export function View({            )}          </section>        )} -      {!reviewing && reviewed && ( -        <section> -          <LinkSuccess upperCased onClick={() => onReview(true)}> -            {i18n.str`Show terms of service`} -          </LinkSuccess> -        </section> -      )}        {terms.status === "notfound" && (          <section>            <WarningText> @@ -204,79 +147,14 @@ export function View({            </WarningText>          </section>        )} -      {reviewing && ( -        <section> -          {terms.status !== "accepted" && -            terms.value && -            terms.value.type === "xml" && ( -              <TermsOfService> -                <ExchangeXmlTos doc={terms.value.document} /> -              </TermsOfService> -            )} -          {terms.status !== "accepted" && -            terms.value && -            terms.value.type === "plain" && ( -              <div style={{ textAlign: "left" }}> -                <pre>{terms.value.content}</pre> -              </div> -            )} -          {terms.status !== "accepted" && -            terms.value && -            terms.value.type === "html" && ( -              <iframe src={terms.value.href.toString()} /> -            )} -          {terms.status !== "accepted" && -            terms.value && -            terms.value.type === "pdf" && ( -              <a href={terms.value.location.toString()} download="tos.pdf"> -                Download Terms of Service -              </a> -            )} -        </section> -      )} -      {reviewing && reviewed && ( -        <section> -          <LinkSuccess upperCased onClick={() => onReview(false)}> -            {i18n.str`Hide terms of service`} -          </LinkSuccess> -        </section> -      )} -      {(reviewing || reviewed) && ( -        <section> -          <CheckboxOutlined -            name="terms" -            enabled={reviewed} -            label={i18n.str`I accept the exchange terms of service`} -            onToggle={() => { -              onAccept(!reviewed); -              onReview(false); -            }} -          /> -        </section> -      )} - -      {/** -       * Main action section -       */} +      <TermsOfServiceSection +        reviewed={reviewed} +        reviewing={reviewing} +        terms={terms} +        onAccept={onAccept} +        onReview={onReview} +      />        <section> -        {terms.status === "new" && !reviewed && !reviewing && ( -          <ButtonSuccess -            upperCased -            disabled={!exchangeBaseUrl} -            onClick={() => onReview(true)} -          > -            {i18n.str`Review exchange terms of service`} -          </ButtonSuccess> -        )} -        {terms.status === "changed" && !reviewed && !reviewing && ( -          <ButtonWarning -            upperCased -            disabled={!exchangeBaseUrl} -            onClick={() => onReview(true)} -          > -            {i18n.str`Review new version of terms of service`} -          </ButtonWarning> -        )}          {(terms.status === "accepted" || (needsReview && reviewed)) && (            <ButtonSuccess              upperCased @@ -310,15 +188,15 @@ export function WithdrawPageWithParsedURI({    const [customExchange, setCustomExchange] = useState<string | undefined>(      undefined,    ); -  const [errorAccepting, setErrorAccepting] = useState<string | undefined>( -    undefined, -  ); +  // const [errorAccepting, setErrorAccepting] = useState<string | undefined>( +  //   undefined, +  // );    const [reviewing, setReviewing] = useState<boolean>(false);    const [reviewed, setReviewed] = useState<boolean>(false);    const [confirmed, setConfirmed] = useState<boolean>(false); -  const knownExchangesHook = useAsyncAsHook(() => listExchanges()); +  const knownExchangesHook = useAsyncAsHook(() => wxApi.listExchanges());    const knownExchanges =      !knownExchangesHook || knownExchangesHook.hasError @@ -329,19 +207,25 @@ export function WithdrawPageWithParsedURI({      (ex) => ex.currency === withdrawAmount.currency,    ); -  const exchange = -    customExchange || -    uriInfo.defaultExchangeBaseUrl || -    thisCurrencyExchanges[0]?.exchangeBaseUrl; +  const exchange: string | undefined = +    customExchange ?? +    uriInfo.defaultExchangeBaseUrl ?? +    (thisCurrencyExchanges[0] +      ? thisCurrencyExchanges[0].exchangeBaseUrl +      : undefined); +    const detailsHook = useAsyncAsHook(async () => {      if (!exchange) throw Error("no default exchange"); -    const tos = await getExchangeTos(exchange, ["text/xml"]); -    const info = await getExchangeWithdrawalInfo({ +    const tos = await wxApi.getExchangeTos(exchange, ["text/xml"]); + +    const tosState = buildTermsOfServiceState(tos); + +    const info = await wxApi.getExchangeWithdrawalInfo({        exchangeBaseUrl: exchange,        amount: withdrawAmount,        tosAcceptedFormat: ["text/xml"],      }); -    return { tos, info }; +    return { tos: tosState, info };    });    if (!detailsHook) { @@ -364,21 +248,24 @@ export function WithdrawPageWithParsedURI({    const details = detailsHook.response;    const onAccept = async (): Promise<void> => { +    if (!exchange) return;      try { -      await setExchangeTosAccepted(exchange, details.tos.currentEtag); +      await wxApi.setExchangeTosAccepted(exchange, details.tos.version);        setReviewed(true);      } catch (e) {        if (e instanceof Error) { -        setErrorAccepting(e.message); +        //FIXME: uncomment this and display error +        // setErrorAccepting(e.message);        }      }    };    const onWithdraw = async (): Promise<void> => { +    if (!exchange) return;      setConfirmed(true);      console.log("accepting exchange", exchange);      try { -      const res = await acceptWithdrawal(uri, exchange); +      const res = await wxApi.acceptWithdrawal(uri, exchange);        console.log("accept withdrawal response", res);        if (res.confirmTransferUrl) {          document.location.href = res.confirmTransferUrl; @@ -388,30 +275,13 @@ export function WithdrawPageWithParsedURI({      }    }; -  const termsContent: TermsDocument | undefined = parseTermsOfServiceContent( -    details.tos.contentType, -    details.tos.content, -  ); - -  const status: TermsStatus = !termsContent -    ? "notfound" -    : !details.tos.acceptedEtag -    ? "new" -    : details.tos.acceptedEtag !== details.tos.currentEtag -    ? "changed" -    : "accepted"; -    return (      <View        onWithdraw={onWithdraw} -      // details={details.tos}        amount={withdrawAmount}        exchangeBaseUrl={exchange}        withdrawalFee={details.info.withdrawFee} //FIXME -      terms={{ -        status, -        value: termsContent, -      }} +      terms={detailsHook.response.tos}        onSwitchExchange={setCustomExchange}        knownExchanges={knownExchanges}        confirmed={confirmed} @@ -426,7 +296,7 @@ export function WithdrawPage({ talerWithdrawUri }: Props): VNode {    const uriInfoHook = useAsyncAsHook(() =>      !talerWithdrawUri        ? Promise.reject(undefined) -      : getWithdrawalDetailsForUri({ talerWithdrawUri }), +      : wxApi.getWithdrawalDetailsForUri({ talerWithdrawUri }),    );    if (!talerWithdrawUri) { @@ -459,46 +329,3 @@ export function WithdrawPage({ talerWithdrawUri }: Props): VNode {      />    );  } - -function parseTermsOfServiceContent( -  type: string, -  text: string, -): TermsDocument | undefined { -  if (type === "text/xml") { -    try { -      const document = new DOMParser().parseFromString(text, "text/xml"); -      return { type: "xml", document }; -    } catch (e) { -      console.log(e); -    } -  } else if (type === "text/html") { -    try { -      const href = new URL(text); -      return { type: "html", href }; -    } catch (e) { -      console.log(e); -    } -  } else if (type === "text/json") { -    try { -      const data = JSON.parse(text); -      return { type: "json", data }; -    } catch (e) { -      console.log(e); -    } -  } else if (type === "text/pdf") { -    try { -      const location = new URL(text); -      return { type: "pdf", location }; -    } catch (e) { -      console.log(e); -    } -  } else if (type === "text/plain") { -    try { -      const content = text; -      return { type: "plain", content }; -    } catch (e) { -      console.log(e); -    } -  } -  return undefined; -} diff --git a/packages/taler-wallet-webextension/src/cta/termsExample.ts b/packages/taler-wallet-webextension/src/cta/termsExample.ts new file mode 100644 index 000000000..d42e49c86 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/termsExample.ts @@ -0,0 +1,781 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +export const termsHtml = `<html xmlns="http://www.w3.org/1999/xhtml" lang="en"> +<head> +  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +  <title>Terms Of Service — Taler Terms of Service</title> +</head><body> +  <div> +    Terms of service +  </div> +  <div> +    A complete separated html with it's own design +  </div> +</body> +</html> +`; +export const termsPlain = ` +Terms Of Service +**************** + +Last Updated: 12.4.2019 + +Welcome! Taler Systems SA (“we,” “our,” or “us”) provides a payment +service through our Internet presence (collectively the “Services”). +Before using our Services, please read the Terms of Service (the +“Terms” or the “Agreement”) carefully. + + +Overview +======== + +This section provides a brief summary of the highlights of this +Agreement. Please note that when you accept this Agreement, you are +accepting all of the terms and conditions and not just this section. +We and possibly other third parties provide Internet services which +interact with the Taler Wallet’s self-hosted personal payment +application. When using the Taler Wallet to interact with our +Services, you are agreeing to our Terms, so please read carefully. + + +Highlights: +----------- + +   * You are responsible for keeping the data in your Taler Wallet at +     all times under your control. Any losses arising from you not +     being in control of your private information are your problem. + +   * We will try to transfer funds we hold in escrow for our users to +     any legal recipient to the best of our ability within the +     limitations of the law and our implementation. However, the +     Services offered today are highly experimental and the set of +     recipients of funds is severely restricted. + +   * For our Services, we may charge transaction fees. The specific +     fee structure is provided based on the Taler protocol and should +     be shown to you when you withdraw electronic coins using a Taler +     Wallet. You agree and understand that the Taler protocol allows +     for the fee structure to change. + +   * You agree to not intentionally overwhelm our systems with +     requests and follow responsible disclosure if you find security +     issues in our services. + +   * We cannot be held accountable for our Services not being +     available due to circumstances beyond our control. If we modify +     or terminate our services, we will try to give you the +     opportunity to recover your funds. However, given the +     experimental state of the Services today, this may not be +     possible. You are strongly advised to limit your use of the +     Service to small-scale experiments expecting total loss of all +     funds. + +These terms outline approved uses of our Services. The Services and +these Terms are still at an experimental stage. If you have any +questions or comments related to this Agreement, please send us a +message to legal@taler-systems.com. If you do not agree to this +Agreement, you must not use our Services. + + +How you accept this policy +========================== + +By sending funds to us (to top-up your Taler Wallet), you acknowledge +that you have read, understood, and agreed to these Terms. We reserve +the right to change these Terms at any time. If you disagree with the +change, we may in the future offer you with an easy option to recover +your unspent funds. However, in the current experimental period you +acknowledge that this feature is not yet available, resulting in your +funds being lost unless you accept the new Terms. If you continue to +use our Services other than to recover your unspent funds, your +continued use of our Services following any such change will signify +your acceptance to be bound by the then current Terms. Please check +the effective date above to determine if there have been any changes +since you have last reviewed these Terms. + + +Services +======== + +We will try to transfer funds that we hold in escrow for our users to +any legal recipient to the best of our ability and within the +limitations of the law and our implementation. However, the Services +offered today are highly experimental and the set of recipients of +funds is severely restricted.  The Taler Wallet can be loaded by +exchanging fiat currencies against electronic coins. We are providing +this exchange service. Once your Taler Wallet is loaded with +electronic coins they can be spent for purchases if the seller is +accepting Taler as a means of payment. We are not guaranteeing that +any seller is accepting Taler at all or a particular seller.  The +seller or recipient of deposits of electronic coins must specify the +target account, as per the design of the Taler protocol. They are +responsible for following the protocol and specifying the correct bank +account, and are solely liable for any losses that may arise from +specifying the wrong account. We will allow the government to link +wire transfers to the underlying contract hash. It is the +responsibility of recipients to preserve the full contracts and to pay +whatever taxes and charges may be applicable. Technical issues may +lead to situations where we are unable to make transfers at all or +lead to incorrect transfers that cannot be reversed. We will only +refuse to execute transfers if the transfers are prohibited by a +competent legal authority and we are ordered to do so. + + +Fees +==== + +You agree to pay the fees for exchanges and withdrawals completed via +the Taler Wallet ("Fees") as defined by us, which we may change from +time to time. With the exception of wire transfer fees, Taler +transaction fees are set for any electronic coin at the time of +withdrawal and fixed throughout the validity period of the respective +electronic coin. Your wallet should obtain and display applicable fees +when withdrawing funds. Fees for coins obtained as change may differ +from the fees applicable to the original coin. Wire transfer fees that +are independent from electronic coins may change annually.  You +authorize us to charge or deduct applicable fees owed in connection +with deposits, exchanges and withdrawals following the rules of the +Taler protocol. We reserve the right to provide different types of +rewards to users either in the form of discount for our Services or in +any other form at our discretion and without prior notice to you. + + +Eligibility +=========== + +To be eligible to use our Services, you must be able to form legally +binding contracts or have the permission of your legal guardian. By +using our Services, you represent and warrant that you meet all +eligibility requirements that we outline in these Terms. + + +Financial self-responsibility +============================= + +You will be responsible for maintaining the availability, integrity +and confidentiality of the data stored in your wallet. When you setup +a Taler Wallet, you are strongly advised to follow the precautionary +measures offered by the software to minimize the chances to losse +access to or control over your Wallet data. We will not be liable for +any loss or damage arising from your failure to comply with this +paragraph. + + +Copyrights and trademarks +========================= + +The Taler Wallet is released under the terms of the GNU General Public +License (GNU GPL). You have the right to access, use, and share the +Taler Wallet, in modified or unmodified form. However, the GPL is a +strong copyleft license, which means that any derivative works must be +distributed under the same license terms as the original software. If +you have any questions, you should review the GNU GPL’s full terms and +conditions at https://www.gnu.org/licenses/gpl-3.0.en.html.  “Taler” +itself is a trademark of Taler Systems SA. You are welcome to use the +name in relation to processing payments using the Taler protocol, +assuming your use is compatible with an official release from the GNU +Project that is not older than two years. + + +Your use of our services +======================== + +When using our Services, you agree to not take any action that +intentionally imposes an unreasonable load on our infrastructure. If +you find security problems in our Services, you agree to first report +them to security@taler-systems.com and grant us the right to publish +your report. We warrant that we will ourselves publicly disclose any +issues reported within 3 months, and that we will not prosecute anyone +reporting security issues if they did not exploit the issue beyond a +proof-of-concept, and followed the above responsible disclosure +practice. + + +Limitation of liability & disclaimer of warranties +================================================== + +You understand and agree that we have no control over, and no duty to +take any action regarding: Failures, disruptions, errors, or delays in +processing that you may experience while using our Services; The risk +of failure of hardware, software, and Internet connections; The risk +of malicious software being introduced or found in the software +underlying the Taler Wallet; The risk that third parties may obtain +unauthorized access to information stored within your Taler Wallet, +including, but not limited to your Taler Wallet coins or backup +encryption keys.  You release us from all liability related to any +losses, damages, or claims arising from: + +1. user error such as forgotten passwords, incorrectly constructed +   transactions; + +2. server failure or data loss; + +3. unauthorized access to the Taler Wallet application; + +4. bugs or other errors in the Taler Wallet software; and + +5. any unauthorized third party activities, including, but not limited +   to, the use of viruses, phishing, brute forcing, or other means of +   attack against the Taler Wallet. We make no representations +   concerning any Third Party Content contained in or accessed through +   our Services. + +Any other terms, conditions, warranties, or representations associated +with such content, are solely between you and such organizations +and/or individuals. + + +Limitation of liability +======================= + +To the fullest extent permitted by applicable law, in no event will we +or any of our officers, directors, representatives, agents, servants, +counsel, employees, consultants, lawyers, and other personnel +authorized to act, acting, or purporting to act on our behalf +(collectively the “Taler Parties”) be liable to you under contract, +tort, strict liability, negligence, or any other legal or equitable +theory, for: + +1. any lost profits, data loss, cost of procurement of substitute +   goods or services, or direct, indirect, incidental, special, +   punitive, compensatory, or consequential damages of any kind +   whatsoever resulting from: + +   1. your use of, or conduct in connection with, our services; + +   2. any unauthorized use of your wallet and/or private key due to +      your failure to maintain the confidentiality of your wallet; + +   3. any interruption or cessation of transmission to or from the +      services; or + +   4. any bugs, viruses, trojan horses, or the like that are found in +      the Taler Wallet software or that may be transmitted to or +      through our services by any third party (regardless of the +      source of origination), or + +2. any direct damages. + +These limitations apply regardless of legal theory, whether based on +tort, strict liability, breach of contract, breach of warranty, or any +other legal theory, and whether or not we were advised of the +possibility of such damages. Some jurisdictions do not allow the +exclusion or limitation of liability for consequential or incidental +damages, so the above limitation may not apply to you. + + +Warranty disclaimer +=================== + +Our services are provided "as is" and without warranty of any kind. To +the maximum extent permitted by law, we disclaim all representations +and warranties, express or implied, relating to the services and +underlying software or any content on the services, whether provided +or owned by us or by any third party, including without limitation, +warranties of merchantability, fitness for a particular purpose, +title, non-infringement, freedom from computer virus, and any implied +warranties arising from course of dealing, course of performance, or +usage in trade, all of which are expressly disclaimed. In addition, we +do not represent or warrant that the content accessible via the +services is accurate, complete, available, current, free of viruses or +other harmful components, or that the results of using the services +will meet your requirements. Some states do not allow the disclaimer +of implied warranties, so the foregoing disclaimers may not apply to +you. This paragraph gives you specific legal rights and you may also +have other legal rights that vary from state to state. + + +Indemnity +========= + +To the extent permitted by applicable law, you agree to defend, +indemnify, and hold harmless the Taler Parties from and against any +and all claims, damages, obligations, losses, liabilities, costs or +debt, and expenses (including, but not limited to, attorney’s fees) +arising from: (a) your use of and access to the Services; (b) any +feedback or submissions you provide to us concerning the Taler Wallet; +(c) your violation of any term of this Agreement; or (d) your +violation of any law, rule, or regulation, or the rights of any third +party. + + +Time limitation on claims +========================= + +You agree that any claim you may have arising out of or related to +your relationship with us must be filed within one year after such +claim arises, otherwise, your claim in permanently barred. + + +Governing law +============= + +No matter where you’re located, the laws of Switzerland will govern +these Terms. If any provisions of these Terms are inconsistent with +any applicable law, those provisions will be superseded or modified +only to the extent such provisions are inconsistent. The parties agree +to submit to the ordinary courts in Zurich, Switzerland for exclusive +jurisdiction of any dispute arising out of or related to your use of +the Services or your breach of these Terms. + + +Termination +=========== + +In the event of termination concerning your use of our Services, your +obligations under this Agreement will still continue. + + +Discontinuance of services +========================== + +We may, in our sole discretion and without cost to you, with or +without prior notice, and at any time, modify or discontinue, +temporarily or permanently, any portion of our Services. We will use +the Taler protocol’s provisions to notify Wallets if our Services are +to be discontinued. It is your responsibility to ensure that the Taler +Wallet is online at least once every three months to observe these +notifications. We shall not be held responsible or liable for any loss +of funds in the event that we discontinue or depreciate the Services +and your Taler Wallet fails to transfer out the coins within a three +months notification period. + + +No waiver +========= + +Our failure to exercise or delay in exercising any right, power, or +privilege under this Agreement shall not operate as a waiver; nor +shall any single or partial exercise of any right, power, or privilege +preclude any other or further exercise thereof. + + +Severability +============ + +If it turns out that any part of this Agreement is invalid, void, or +for any reason unenforceable, that term will be deemed severable and +limited or eliminated to the minimum extent necessary. + + +Force majeure +============= + +We shall not be held liable for any delays, failure in performance, or +interruptions of service which result directly or indirectly from any +cause or condition beyond our reasonable control, including but not +limited to: any delay or failure due to any act of God, act of civil +or military authorities, act of terrorism, civil disturbance, war, +strike or other labor dispute, fire, interruption in +telecommunications or Internet services or network provider services, +failure of equipment and/or software, other catastrophe, or any other +occurrence which is beyond our reasonable control and shall not affect +the validity and enforceability of any remaining provisions. + + +Assignment +========== + +You agree that we may assign any of our rights and/or transfer, sub- +contract, or delegate any of our obligations under these Terms. + + +Entire agreement +================ + +This Agreement sets forth the entire understanding and agreement as to +the subject matter hereof and supersedes any and all prior +discussions, agreements, and understandings of any kind (including, +without limitation, any prior versions of this Agreement) and every +nature between us. Except as provided for above, any modification to +this Agreement must be in writing and must be signed by both parties. + + +Questions or comments +===================== + +We welcome comments, questions, concerns, or suggestions. Please send +us a message on our contact page at legal@taler-systems.com. + +`; + +export const termsXml = `<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd"> +<!-- Generated by Docutils 0.14 --> +<document source="/home/grothoff/research/taler/exchange/contrib/tos/tos.rst"> +    <section ids="terms-of-service" names="terms\ of\ service"> +        <title>Terms Of Service</title> +        <paragraph>Last Updated: 12.4.2019</paragraph> +        <paragraph>Welcome! Taler Systems SA (“we,” “our,” or “us”) provides a payment service +            through our Internet presence (collectively the “Services”). Before using our +            Services, please read the Terms of Service (the “Terms” or the “Agreement”) +            carefully.</paragraph> +        <section ids="overview" names="overview"> +            <title>Overview</title> +            <paragraph>This section provides a brief summary of the highlights of this +                Agreement. Please note that when you accept this Agreement, you are accepting +                all of the terms and conditions and not just this section. We and possibly +                other third parties provide Internet services which interact with the Taler +                Wallet’s self-hosted personal payment application. When using the Taler Wallet +                to interact with our Services, you are agreeing to our Terms, so please read +                carefully.</paragraph> +            <section ids="highlights" names="highlights:"> +                <title>Highlights:</title> +                <block_quote> +                    <bullet_list bullet="•"> +                        <list_item> +                            <paragraph>You are responsible for keeping the data in your Taler Wallet at all times +                                under your control. Any losses arising from you not being in control of +                                your private information are your problem.</paragraph> +                        </list_item> +                        <list_item> +                            <paragraph>We will try to transfer funds we hold in escrow for our users to any legal +                                recipient to the best of our ability within the limitations of the law and +                                our implementation. However, the Services offered today are highly +                                experimental and the set of recipients of funds is severely restricted.</paragraph> +                        </list_item> +                        <list_item> +                            <paragraph>For our Services, we may charge transaction fees. The specific fee structure +                                is provided based on the Taler protocol and should be shown to you when you +                                withdraw electronic coins using a Taler Wallet. You agree and understand +                                that the Taler protocol allows for the fee structure to change.</paragraph> +                        </list_item> +                        <list_item> +                            <paragraph>You agree to not intentionally overwhelm our systems with requests and +                                follow responsible disclosure if you find security issues in our services.</paragraph> +                        </list_item> +                        <list_item> +                            <paragraph>We cannot be held accountable for our Services not being available due to +                                circumstances beyond our control. If we modify or terminate our services, +                                we will try to give you the opportunity to recover your funds. However, +                                given the experimental state of the Services today, this may not be +                                possible. You are strongly advised to limit your use of the Service +                                to small-scale experiments expecting total loss of all funds.</paragraph> +                        </list_item> +                    </bullet_list> +                </block_quote> +                <paragraph>These terms outline approved uses of our Services. The Services and these +                    Terms are still at an experimental stage. If you have any questions or +                    comments related to this Agreement, please send us a message to +                    <reference refuri="mailto:legal@taler-systems.com">legal@taler-systems.com</reference>. If you do not agree to this Agreement, you must not +                    use our Services.</paragraph> +            </section> +        </section> +        <section ids="how-you-accept-this-policy" names="how\ you\ accept\ this\ policy"> +            <title>How you accept this policy</title> +            <paragraph>By sending funds to us (to top-up your Taler Wallet), you acknowledge that you +                have read, understood, and agreed to these Terms. We reserve the right to +                change these Terms at any time. If you disagree with the change, we may in the +                future offer you with an easy option to recover your unspent funds. However, +                in the current experimental period you acknowledge that this feature is not +                yet available, resulting in your funds being lost unless you accept the new +                Terms. If you continue to use our Services other than to recover your unspent +                funds, your continued use of our Services following any such change will +                signify your acceptance to be bound by the then current Terms. Please check +                the effective date above to determine if there have been any changes since you +                have last reviewed these Terms.</paragraph> +        </section> +        <section ids="services" names="services"> +            <title>Services</title> +            <paragraph>We will try to transfer funds that we hold in escrow for our users to any +                legal recipient to the best of our ability and within the limitations of the +                law and our implementation. However, the Services offered today are highly +                experimental and the set of recipients of funds is severely restricted.  The +                Taler Wallet can be loaded by exchanging fiat currencies against electronic +                coins. We are providing this exchange service. Once your Taler Wallet is +                loaded with electronic coins they can be spent for purchases if the seller is +                accepting Taler as a means of payment. We are not guaranteeing that any seller +                is accepting Taler at all or a particular seller.  The seller or recipient of +                deposits of electronic coins must specify the target account, as per the +                design of the Taler protocol. They are responsible for following the protocol +                and specifying the correct bank account, and are solely liable for any losses +                that may arise from specifying the wrong account. We will allow the government +                to link wire transfers to the underlying contract hash. It is the +                responsibility of recipients to preserve the full contracts and to pay +                whatever taxes and charges may be applicable. Technical issues may lead to +                situations where we are unable to make transfers at all or lead to incorrect +                transfers that cannot be reversed. We will only refuse to execute transfers if +                the transfers are prohibited by a competent legal authority and we are ordered +                to do so.</paragraph> +        </section> +        <section ids="fees" names="fees"> +            <title>Fees</title> +            <paragraph>You agree to pay the fees for exchanges and withdrawals completed via the +                Taler Wallet (“Fees”) as defined by us, which we may change from time to +                time. With the exception of wire transfer fees, Taler transaction fees are set +                for any electronic coin at the time of withdrawal and fixed throughout the +                validity period of the respective electronic coin. Your wallet should obtain +                and display applicable fees when withdrawing funds. Fees for coins obtained as +                change may differ from the fees applicable to the original coin. Wire transfer +                fees that are independent from electronic coins may change annually.  You +                authorize us to charge or deduct applicable fees owed in connection with +                deposits, exchanges and withdrawals following the rules of the Taler protocol. +                We reserve the right to provide different types of rewards to users either in +                the form of discount for our Services or in any other form at our discretion +                and without prior notice to you.</paragraph> +        </section> +        <section ids="eligibility" names="eligibility"> +            <title>Eligibility</title> +            <paragraph>To be eligible to use our Services, you must be able to form legally binding +                contracts or have the permission of your legal guardian. By using our +                Services, you represent and warrant that you meet all eligibility requirements +                that we outline in these Terms.</paragraph> +        </section> +        <section ids="financial-self-responsibility" names="financial\ self-responsibility"> +            <title>Financial self-responsibility</title> +            <paragraph>You will be responsible for maintaining the availability, integrity and +                confidentiality of the data stored in your wallet. When you setup a Taler +                Wallet, you are strongly advised to follow the precautionary measures offered +                by the software to minimize the chances to losse access to or control over +                your Wallet data. We will not be liable for any loss or damage arising from +                your failure to comply with this paragraph.</paragraph> +        </section> +        <section ids="copyrights-and-trademarks" names="copyrights\ and\ trademarks"> +            <title>Copyrights and trademarks</title> +            <paragraph>The Taler Wallet is released under the terms of the GNU General Public License +                (GNU GPL). You have the right to access, use, and share the Taler Wallet, in +                modified or unmodified form. However, the GPL is a strong copyleft license, +                which means that any derivative works must be distributed under the same +                license terms as the original software. If you have any questions, you should +                review the GNU GPL’s full terms and conditions at +                <reference refuri="https://www.gnu.org/licenses/gpl-3.0.en.html">https://www.gnu.org/licenses/gpl-3.0.en.html</reference>.  “Taler” itself is a trademark +                of Taler Systems SA. You are welcome to use the name in relation to processing +                payments using the Taler protocol, assuming your use is compatible with an +                official release from the GNU Project that is not older than two years.</paragraph> +        </section> +        <section ids="your-use-of-our-services" names="your\ use\ of\ our\ services"> +            <title>Your use of our services</title> +            <paragraph>When using our Services, you agree to not take any action that intentionally +                imposes an unreasonable load on our infrastructure. If you find security +                problems in our Services, you agree to first report them to +                <reference refuri="mailto:security@taler-systems.com">security@taler-systems.com</reference> and grant us the right to publish your report. We +                warrant that we will ourselves publicly disclose any issues reported within 3 +                months, and that we will not prosecute anyone reporting security issues if +                they did not exploit the issue beyond a proof-of-concept, and followed the +                above responsible disclosure practice.</paragraph> +        </section> +        <section ids="limitation-of-liability-disclaimer-of-warranties" names="limitation\ of\ liability\ &\ disclaimer\ of\ warranties"> +            <title>Limitation of liability & disclaimer of warranties</title> +            <paragraph>You understand and agree that we have no control over, and no duty to take any +                action regarding: Failures, disruptions, errors, or delays in processing that +                you may experience while using our Services; The risk of failure of hardware, +                software, and Internet connections; The risk of malicious software being +                introduced or found in the software underlying the Taler Wallet; The risk that +                third parties may obtain unauthorized access to information stored within your +                Taler Wallet, including, but not limited to your Taler Wallet coins or backup +                encryption keys.  You release us from all liability related to any losses, +                damages, or claims arising from:</paragraph> +            <enumerated_list enumtype="loweralpha" prefix="(" suffix=")"> +                <list_item> +                    <paragraph>user error such as forgotten passwords, incorrectly constructed +                        transactions;</paragraph> +                </list_item> +                <list_item> +                    <paragraph>server failure or data loss;</paragraph> +                </list_item> +                <list_item> +                    <paragraph>unauthorized access to the Taler Wallet application;</paragraph> +                </list_item> +                <list_item> +                    <paragraph>bugs or other errors in the Taler Wallet software; and</paragraph> +                </list_item> +                <list_item> +                    <paragraph>any unauthorized third party activities, including, but not limited to, +                        the use of viruses, phishing, brute forcing, or other means of attack +                        against the Taler Wallet. We make no representations concerning any +                        Third Party Content contained in or accessed through our Services.</paragraph> +                </list_item> +            </enumerated_list> +            <paragraph>Any other terms, conditions, warranties, or representations associated with +                such content, are solely between you and such organizations and/or +                individuals.</paragraph> +        </section> +        <section ids="limitation-of-liability" names="limitation\ of\ liability"> +            <title>Limitation of liability</title> +            <paragraph>To the fullest extent permitted by applicable law, in no event will we or any +                of our officers, directors, representatives, agents, servants, counsel, +                employees, consultants, lawyers, and other personnel authorized to act, +                acting, or purporting to act on our behalf (collectively the “Taler Parties”) +                be liable to you under contract, tort, strict liability, negligence, or any +                other legal or equitable theory, for:</paragraph> +            <enumerated_list enumtype="loweralpha" prefix="(" suffix=")"> +                <list_item> +                    <paragraph>any lost profits, data loss, cost of procurement of substitute goods or +                        services, or direct, indirect, incidental, special, punitive, compensatory, +                        or consequential damages of any kind whatsoever resulting from:</paragraph> +                </list_item> +            </enumerated_list> +            <block_quote> +                <enumerated_list enumtype="lowerroman" prefix="(" suffix=")"> +                    <list_item> +                        <paragraph>your use of, or conduct in connection with, our services;</paragraph> +                    </list_item> +                    <list_item> +                        <paragraph>any unauthorized use of your wallet and/or private key due to your +                            failure to maintain the confidentiality of your wallet;</paragraph> +                    </list_item> +                    <list_item> +                        <paragraph>any interruption or cessation of transmission to or from the services; or</paragraph> +                    </list_item> +                    <list_item> +                        <paragraph>any bugs, viruses, trojan horses, or the like that are found in the Taler +                            Wallet software or that may be transmitted to or through our services by +                            any third party (regardless of the source of origination), or</paragraph> +                    </list_item> +                </enumerated_list> +            </block_quote> +            <enumerated_list enumtype="loweralpha" prefix="(" start="2" suffix=")"> +                <list_item> +                    <paragraph>any direct damages.</paragraph> +                </list_item> +            </enumerated_list> +            <paragraph>These limitations apply regardless of legal theory, whether based on tort, +                strict liability, breach of contract, breach of warranty, or any other legal +                theory, and whether or not we were advised of the possibility of such +                damages. Some jurisdictions do not allow the exclusion or limitation of +                liability for consequential or incidental damages, so the above limitation may +                not apply to you.</paragraph> +        </section> +        <section ids="warranty-disclaimer" names="warranty\ disclaimer"> +            <title>Warranty disclaimer</title> +            <paragraph>Our services are provided “as is” and without warranty of any kind. To the +                maximum extent permitted by law, we disclaim all representations and +                warranties, express or implied, relating to the services and underlying +                software or any content on the services, whether provided or owned by us or by +                any third party, including without limitation, warranties of merchantability, +                fitness for a particular purpose, title, non-infringement, freedom from +                computer virus, and any implied warranties arising from course of dealing, +                course of performance, or usage in trade, all of which are expressly +                disclaimed. In addition, we do not represent or warrant that the content +                accessible via the services is accurate, complete, available, current, free of +                viruses or other harmful components, or that the results of using the services +                will meet your requirements. Some states do not allow the disclaimer of +                implied warranties, so the foregoing disclaimers may not apply to you. This +                paragraph gives you specific legal rights and you may also have other legal +                rights that vary from state to state.</paragraph> +        </section> +        <section ids="indemnity" names="indemnity"> +            <title>Indemnity</title> +            <paragraph>To the extent permitted by applicable law, you agree to defend, indemnify, and +                hold harmless the Taler Parties from and against any and all claims, damages, +                obligations, losses, liabilities, costs or debt, and expenses (including, but +                not limited to, attorney’s fees) arising from: (a) your use of and access to +                the Services; (b) any feedback or submissions you provide to us concerning the +                Taler Wallet; (c) your violation of any term of this Agreement; or (d) your +                violation of any law, rule, or regulation, or the rights of any third party.</paragraph> +        </section> +        <section ids="time-limitation-on-claims" names="time\ limitation\ on\ claims"> +            <title>Time limitation on claims</title> +            <paragraph>You agree that any claim you may have arising out of or related to your +                relationship with us must be filed within one year after such claim arises, +                otherwise, your claim in permanently barred.</paragraph> +        </section> +        <section ids="governing-law" names="governing\ law"> +            <title>Governing law</title> +            <paragraph>No matter where you’re located, the laws of Switzerland will govern these +                Terms. If any provisions of these Terms are inconsistent with any applicable +                law, those provisions will be superseded or modified only to the extent such +                provisions are inconsistent. The parties agree to submit to the ordinary +                courts in Zurich, Switzerland for exclusive jurisdiction of any dispute +                arising out of or related to your use of the Services or your breach of these +                Terms.</paragraph> +        </section> +        <section ids="termination" names="termination"> +            <title>Termination</title> +            <paragraph>In the event of termination concerning your use of our Services, your +                obligations under this Agreement will still continue.</paragraph> +        </section> +        <section ids="discontinuance-of-services" names="discontinuance\ of\ services"> +            <title>Discontinuance of services</title> +            <paragraph>We may, in our sole discretion and without cost to you, with or without prior +                notice, and at any time, modify or discontinue, temporarily or permanently, +                any portion of our Services. We will use the Taler protocol’s provisions to +                notify Wallets if our Services are to be discontinued. It is your +                responsibility to ensure that the Taler Wallet is online at least once every +                three months to observe these notifications. We shall not be held responsible +                or liable for any loss of funds in the event that we discontinue or depreciate +                the Services and your Taler Wallet fails to transfer out the coins within a +                three months notification period.</paragraph> +        </section> +        <section ids="no-waiver" names="no\ waiver"> +            <title>No waiver</title> +            <paragraph>Our failure to exercise or delay in exercising any right, power, or privilege +                under this Agreement shall not operate as a waiver; nor shall any single or +                partial exercise of any right, power, or privilege preclude any other or +                further exercise thereof.</paragraph> +        </section> +        <section ids="severability" names="severability"> +            <title>Severability</title> +            <paragraph>If it turns out that any part of this Agreement is invalid, void, or for any +                reason unenforceable, that term will be deemed severable and limited or +                eliminated to the minimum extent necessary.</paragraph> +        </section> +        <section ids="force-majeure" names="force\ majeure"> +            <title>Force majeure</title> +            <paragraph>We shall not be held liable for any delays, failure in performance, or +                interruptions of service which result directly or indirectly from any cause or +                condition beyond our reasonable control, including but not limited to: any +                delay or failure due to any act of God, act of civil or military authorities, +                act of terrorism, civil disturbance, war, strike or other labor dispute, fire, +                interruption in telecommunications or Internet services or network provider +                services, failure of equipment and/or software, other catastrophe, or any +                other occurrence which is beyond our reasonable control and shall not affect +                the validity and enforceability of any remaining provisions.</paragraph> +        </section> +        <section ids="assignment" names="assignment"> +            <title>Assignment</title> +            <paragraph>You agree that we may assign any of our rights and/or transfer, sub-contract, +                or delegate any of our obligations under these Terms.</paragraph> +        </section> +        <section ids="entire-agreement" names="entire\ agreement"> +            <title>Entire agreement</title> +            <paragraph>This Agreement sets forth the entire understanding and agreement as to the +                subject matter hereof and supersedes any and all prior discussions, +                agreements, and understandings of any kind (including, without limitation, any +                prior versions of this Agreement) and every nature between us. Except as +                provided for above, any modification to this Agreement must be in writing and +                must be signed by both parties.</paragraph> +        </section> +        <section ids="questions-or-comments" names="questions\ or\ comments"> +            <title>Questions or comments</title> +            <paragraph>We welcome comments, questions, concerns, or suggestions. Please send us a +                message on our contact page at <reference refuri="mailto:legal@taler-systems.com">legal@taler-systems.com</reference>.</paragraph> +        </section> +    </section> +</document> +`; + +export const termsPdf = ` +%PDF-1.2  +9 0 obj << >>  +stream +BT/ 9 Tf(This is the Exchange TERMS OF SERVICE)' ET +endstream +endobj +4 0 obj << /Type /Page /Parent 5 0 R /Contents 9 0 R >> endobj  +5 0 obj << /Kids [4 0 R ] /Count 1 /Type /Pages /MediaBox [ 0 0 180 20 ] >> endobj +3 0 obj << /Pages 5 0 R /Type /Catalog >> endobj +trailer +<< /Root 3 0 R >> +%%EOF +`; + diff --git a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx index 008f30cb6..33164783d 100644 --- a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx +++ b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx @@ -71,6 +71,11 @@ export function BalanceView({              <Linker pageName="/welcome">help</Linker> getting started?            </i18n.Translate>          </p> +        <footer style={{ justifyContent: "space-around" }}> +          <ButtonPrimary onClick={goToWalletManualWithdraw}> +            Withdraw +          </ButtonPrimary> +        </footer>        </Fragment>      );    } diff --git a/packages/taler-wallet-webextension/src/popup/Settings.stories.tsx b/packages/taler-wallet-webextension/src/popup/Settings.stories.tsx index ae8e54ba1..069157475 100644 --- a/packages/taler-wallet-webextension/src/popup/Settings.stories.tsx +++ b/packages/taler-wallet-webextension/src/popup/Settings.stories.tsx @@ -30,13 +30,8 @@ export default {    },  }; -export const AllOff = createExample(TestedComponent, { -  deviceName: "this-is-the-device-name", -  setDeviceName: () => Promise.resolve(), -}); +export const AllOff = createExample(TestedComponent, {});  export const OneChecked = createExample(TestedComponent, { -  deviceName: "this-is-the-device-name",    permissionsEnabled: true, -  setDeviceName: () => Promise.resolve(),  }); diff --git a/packages/taler-wallet-webextension/src/popup/Settings.tsx b/packages/taler-wallet-webextension/src/popup/Settings.tsx index 0a3f777d5..84ecea4fe 100644 --- a/packages/taler-wallet-webextension/src/popup/Settings.tsx +++ b/packages/taler-wallet-webextension/src/popup/Settings.tsx @@ -14,36 +14,18 @@   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>  */ -import { ExchangeListItem, i18n } from "@gnu-taler/taler-util"; +import { i18n } from "@gnu-taler/taler-util";  import { Fragment, h, VNode } from "preact";  import { Checkbox } from "../components/Checkbox"; -import { ButtonPrimary } from "../components/styled";  import { useDevContext } from "../context/devContext"; -import { useAsyncAsHook } from "../hooks/useAsyncAsHook"; -import { useBackupDeviceName } from "../hooks/useBackupDeviceName";  import { useExtendedPermissions } from "../hooks/useExtendedPermissions"; -import { useLang } from "../hooks/useLang"; -// import { strings as messages } from "../i18n/strings"; -import * as wxApi from "../wxApi";  export function SettingsPage(): VNode {    const [permissionsEnabled, togglePermissions] = useExtendedPermissions();    const { devMode, toggleDevMode } = useDevContext(); -  const { name, update } = useBackupDeviceName(); -  const [lang, changeLang] = useLang(); -  const exchangesHook = useAsyncAsHook(wxApi.listExchanges);    return (      <SettingsView -      lang={lang} -      changeLang={changeLang} -      knownExchanges={ -        !exchangesHook || exchangesHook.hasError -          ? [] -          : exchangesHook.response.exchanges -      } -      deviceName={name} -      setDeviceName={update}        permissionsEnabled={permissionsEnabled}        togglePermissions={togglePermissions}        developerMode={devMode} @@ -53,36 +35,13 @@ export function SettingsPage(): VNode {  }  export interface ViewProps { -  lang: string; -  changeLang: (s: string) => void; -  deviceName: string; -  setDeviceName: (s: string) => Promise<void>;    permissionsEnabled: boolean;    togglePermissions: () => void;    developerMode: boolean;    toggleDeveloperMode: () => void; -  knownExchanges: Array<ExchangeListItem>;  } -// type LangsNames = { -//   [P in keyof typeof messages]: string; -// }; - -// const names: LangsNames = { -//   es: "Español [es]", -//   en: "English [en]", -//   fr: "Français [fr]", -//   de: "Deutsch [de]", -//   sv: "Svenska [sv]", -//   it: "Italiano [it]", -// }; -  export function SettingsView({ -  knownExchanges, -  // lang, -  // changeLang, -  // deviceName, -  // setDeviceName,    permissionsEnabled,    togglePermissions,    developerMode, @@ -92,45 +51,6 @@ export function SettingsView({      <Fragment>        <section>          <h2> -          <i18n.Translate>Known exchanges</i18n.Translate> -        </h2> -        {!knownExchanges || !knownExchanges.length ? ( -          <div>No exchange yet!</div> -        ) : ( -          <Fragment> -            <table> -              {knownExchanges.map((e, idx) => ( -                <tr key={idx}> -                  <td>{e.currency}</td> -                  <td> -                    <a href={e.exchangeBaseUrl}>{e.exchangeBaseUrl}</a> -                  </td> -                </tr> -              ))} -            </table> -          </Fragment> -        )} -        <div style={{ display: "flex", justifyContent: "space-between" }}> -          <div /> -          <ButtonPrimary>Manage exchange</ButtonPrimary> -        </div> -        {/* <h2><i18n.Translate>Wallet</i18n.Translate></h2> */} -        {/* <SelectList -          value={lang} -          onChange={changeLang} -          name="lang" -          list={names} -          label={i18n.str`Language`} -          description="(Choose your preferred lang)" -        /> -        <EditableText -          value={deviceName} -          onChange={setDeviceName} -          name="device-id" -          label={i18n.str`Device name`} -          description="(This is how you will recognize the wallet in the backup provider)" -        /> */} -        <h2>            <i18n.Translate>Permissions</i18n.Translate>          </h2>          <Checkbox diff --git a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx index d0c79f6d4..c6c872f21 100644 --- a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx +++ b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx @@ -38,6 +38,7 @@ import { ProviderAddPage } from "./wallet/ProviderAddPage";  import { ProviderDetailPage } from "./wallet/ProviderDetailPage";  import { SettingsPage } from "./popup/Settings";  import { TalerActionFound } from "./popup/TalerActionFound"; +import { ExchangeAddPage } from "./wallet/ExchangeAddPage";  function main(): void {    try { @@ -127,6 +128,15 @@ function Application() {                  route(Pages.backup);                }}              /> + +            <Route +              path={Pages.exchange_add} +              component={ExchangeAddPage} +              onBack={() => { +                route(Pages.balance); +              }} +            /> +              <Route default component={Redirect} to={Pages.balance} />            </Router>          </PopupBox> diff --git a/packages/taler-wallet-webextension/src/utils/index.ts b/packages/taler-wallet-webextension/src/utils/index.ts new file mode 100644 index 000000000..477818520 --- /dev/null +++ b/packages/taler-wallet-webextension/src/utils/index.ts @@ -0,0 +1,162 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/> + */ + +import { AmountJson, Amounts, GetExchangeTosResult } from "@gnu-taler/taler-util"; + + +function getJsonIfOk(r: Response): Promise<any> { +  if (r.ok) { +    return r.json(); +  } + +  if (r.status >= 400 && r.status < 500) { +    throw new Error(`URL may not be right: (${r.status}) ${r.statusText}`); +  } + +  throw new Error( +    `Try another server: (${r.status}) ${r.statusText || "internal server error" +    }`, +  ); + +} + +export async function queryToSlashConfig<T>( +  url: string, +): Promise<T> { +  return fetch(new URL("config", url).href) +    .catch(() => { +      throw new Error(`Network error`); +    }) +    .then(getJsonIfOk); +} + +export async function queryToSlashKeys<T>( +  url: string, +): Promise<T> { +  return fetch(new URL("keys", url).href) +    .catch(() => { +      throw new Error(`Network error`); +    }) +    .then(getJsonIfOk); +} + +export function buildTermsOfServiceState(tos: GetExchangeTosResult): TermsState { + +  const content: TermsDocument | undefined = parseTermsOfServiceContent( +    tos.contentType, +    tos.content, +  ); + +  const status: TermsStatus = !content +    ? "notfound" +    : !tos.acceptedEtag +      ? "new" +      : tos.acceptedEtag !== tos.currentEtag +        ? "changed" +        : "accepted"; + +  return { content, status, version: tos.currentEtag } +} + +function parseTermsOfServiceContent( +  type: string, +  text: string, +): TermsDocument | undefined { +  if (type === "text/xml") { +    try { +      const document = new DOMParser().parseFromString(text, "text/xml"); +      return { type: "xml", document }; +    } catch (e) { +      console.log(e); +    } +  } else if (type === "text/html") { +    try { +      const href = new URL(text); +      return { type: "html", href }; +    } catch (e) { +      console.log(e); +    } +  } else if (type === "text/json") { +    try { +      const data = JSON.parse(text); +      return { type: "json", data }; +    } catch (e) { +      console.log(e); +    } +  } else if (type === "text/pdf") { +    try { +      const location = new URL(text); +      return { type: "pdf", location }; +    } catch (e) { +      console.log(e); +    } +  } else if (type === "text/plain") { +    try { +      const content = text; +      return { type: "plain", content }; +    } catch (e) { +      console.log(e); +    } +  } +  return undefined; +} + +export type TermsState = { +  content: TermsDocument | undefined; +  status: TermsStatus; +  version: string; +}; + +type TermsStatus = "new" | "accepted" | "changed" | "notfound"; + +type TermsDocument = +  | TermsDocumentXml +  | TermsDocumentHtml +  | TermsDocumentPlain +  | TermsDocumentJson +  | TermsDocumentPdf; + +interface TermsDocumentXml { +  type: "xml"; +  document: Document; +} + +interface TermsDocumentHtml { +  type: "html"; +  href: URL; +} + +interface TermsDocumentPlain { +  type: "plain"; +  content: string; +} + +interface TermsDocumentJson { +  type: "json"; +  data: any; +} + +interface TermsDocumentPdf { +  type: "pdf"; +  location: URL; +} + +export function amountToString(text: AmountJson): string { +  const aj = Amounts.jsonifyAmount(text); +  const amount = Amounts.stringifyValue(aj); +  return `${amount} ${aj.currency}`; +} + diff --git a/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx b/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx index 04d79a5ea..0a8910646 100644 --- a/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx @@ -17,7 +17,7 @@  import { BalancesResponse, i18n } from "@gnu-taler/taler-util";  import { Fragment, h, VNode } from "preact";  import { BalanceTable } from "../components/BalanceTable"; -import { ButtonPrimary, ErrorBox } from "../components/styled/index"; +import { ButtonPrimary, Centered, ErrorBox } from "../components/styled/index";  import { HookResponse, useAsyncAsHook } from "../hooks/useAsyncAsHook";  import { PageLink } from "../renderHtml";  import * as wxApi from "../wxApi"; @@ -66,10 +66,17 @@ export function BalanceView({    if (balance.response.balances.length === 0) {      return (        <p> -        <i18n.Translate> -          You have no balance to show. Need some{" "} -          <Linker pageName="/welcome">help</Linker> getting started? -        </i18n.Translate> +        <Centered style={{ marginTop: 100 }}> +          <i18n.Translate> +            You have no balance to show. Need some{" "} +            <Linker pageName="/welcome">help</Linker> getting started? +          </i18n.Translate> +          <div> +            <ButtonPrimary onClick={goToWalletManualWithdraw}> +              Withdraw +            </ButtonPrimary> +          </div> +        </Centered>        </p>      );    } diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx index 1bceabd20..554952795 100644 --- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx +++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx @@ -21,6 +21,7 @@  import { AmountJson, Amounts, i18n } from "@gnu-taler/taler-util";  import { Fragment, h, VNode } from "preact"; +import { route } from "preact-router";  import { useState } from "preact/hooks";  import { ErrorMessage } from "../components/ErrorMessage";  import { SelectList } from "../components/SelectList"; @@ -32,7 +33,9 @@ import {    Input,    InputWithLabel,    LightText, +  LinkPrimary,  } from "../components/styled"; +import { Pages } from "../NavigationBar";  export interface Props {    error: string | undefined; @@ -87,12 +90,7 @@ export function CreateManualWithdraw({      return (        <Centered style={{ marginTop: 100 }}>          <BoldLight>No exchange configured</BoldLight> -        <ButtonSuccess -          //FIXME: add exchange feature -          onClick={() => { -            null; -          }} -        > +        <ButtonSuccess onClick={() => route(Pages.exchange_add)}>            <i18n.Translate>Add exchange</i18n.Translate>          </ButtonSuccess>        </Centered> @@ -108,8 +106,9 @@ export function CreateManualWithdraw({          />          <h2>Manual Withdrawal</h2>          <LightText> -          Choose a exchange to create a reserve and then fill the reserve to -          withdraw the coins +          Choose a exchange from where the coins will be withdrawn. The exchange +          will send the coins to this wallet after receiving a wire transfer +          with the correct subject.          </LightText>          <p>            <Input> @@ -130,11 +129,14 @@ export function CreateManualWithdraw({                onChange={changeExchange}              />            </Input> -          {/* <p style={{ display: "flex", justifyContent: "right" }}> -            <a href="" style={{ marginLeft: "auto" }}> -              Add new exchange -            </a> -          </p> */} +          <div style={{ display: "flex", justifyContent: "space-between" }}> +            <LinkPrimary +              onClick={() => route(Pages.exchange_add)} +              style={{ marginLeft: "auto" }} +            > +              <i18n.Translate>Add exchange</i18n.Translate> +            </LinkPrimary> +          </div>            {currency && (              <InputWithLabel invalid={!!amount && !parsedAmount}>                <label>Amount</label> diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.stories.tsx new file mode 100644 index 000000000..2e034458a --- /dev/null +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.stories.tsx @@ -0,0 +1,67 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { termsXml } from "../cta/termsExample"; +import { createExample } from "../test-utils"; +import { View as TestedComponent } from "./ExchangeAddConfirm"; + +export default { +  title: "wallet/exchange add/confirm", +  component: TestedComponent, +  argTypes: { +    onRetry: { action: "onRetry" }, +    onDelete: { action: "onDelete" }, +    onBack: { action: "onBack" }, +  }, +}; + +export const TermsNotFound = createExample(TestedComponent, { +  url: "https://exchange.demo.taler.net/", +  terms: { +    status: "notfound", +    version: "1", +    content: undefined, +  }, +  onAccept: async () => undefined, +}); + +export const NewTerms = createExample(TestedComponent, { +  url: "https://exchange.demo.taler.net/", +  terms: { +    status: "new", +    version: "1", +    content: undefined, +  }, +  onAccept: async () => undefined, +}); + +export const TermsChanged = createExample(TestedComponent, { +  url: "https://exchange.demo.taler.net/", +  terms: { +    status: "changed", +    version: "1", +    content: { +      type: "xml", +      document: new DOMParser().parseFromString(termsXml, "text/xml"), +    }, +  }, +  onAccept: async () => undefined, +}); diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx new file mode 100644 index 000000000..5c7f94ecd --- /dev/null +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx @@ -0,0 +1,152 @@ +import { i18n } from "@gnu-taler/taler-util"; +import { Fragment, h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { +  Button, +  ButtonSuccess, +  ButtonWarning, +  WarningBox, +} from "../components/styled/index"; +import { TermsOfServiceSection } from "../cta/TermsOfServiceSection"; +import { useAsyncAsHook } from "../hooks/useAsyncAsHook"; +import { buildTermsOfServiceState, TermsState } from "../utils"; +import * as wxApi from "../wxApi"; + +export interface Props { +  url: string; +  onCancel: () => void; +  onConfirm: () => void; +} + +export function ExchangeAddConfirmPage({ +  url, +  onCancel, +  onConfirm, +}: Props): VNode { +  const detailsHook = useAsyncAsHook(async () => { +    const tos = await wxApi.getExchangeTos(url, ["text/xml"]); + +    const tosState = buildTermsOfServiceState(tos); + +    return { tos: tosState }; +  }); + +  const termsNotFound: TermsState = { +    status: "notfound", +    version: "", +    content: undefined, +  }; +  const terms = !detailsHook +    ? undefined +    : detailsHook.hasError +    ? termsNotFound +    : detailsHook.response.tos; + +  // const [errorAccepting, setErrorAccepting] = useState<string | undefined>( +  //   undefined, +  // ); + +  const onAccept = async (): Promise<void> => { +    if (!terms) return; +    try { +      await wxApi.setExchangeTosAccepted(url, terms.version); +    } catch (e) { +      if (e instanceof Error) { +        // setErrorAccepting(e.message); +      } +    } +  }; +  return ( +    <View +      url={url} +      onAccept={onAccept} +      onCancel={onCancel} +      onConfirm={onConfirm} +      terms={terms} +    /> +  ); +} + +export interface ViewProps { +  url: string; +  terms: TermsState | undefined; +  onAccept: (b: boolean) => Promise<void>; +  onCancel: () => void; +  onConfirm: () => void; +} + +export function View({ +  url, +  terms, +  onAccept: doAccept, +  onConfirm, +  onCancel, +}: ViewProps): VNode { +  const needsReview = +    !terms || terms.status === "changed" || terms.status === "new"; +  const [reviewed, setReviewed] = useState<boolean>(false); + +  return ( +    <Fragment> +      <section> +        <h1>Review terms of service</h1> +        <div> +          Exchange URL: +          <a href={url} target="_blank" rel="noreferrer"> +            {url} +          </a> +        </div> +      </section> +      {terms && terms.status === "notfound" && ( +        <section> +          <WarningBox> +            {i18n.str`Exchange doesn't have terms of service`} +          </WarningBox> +        </section> +      )} + +      {terms && ( +        <TermsOfServiceSection +          reviewed={reviewed} +          reviewing={true} +          terms={terms} +          onAccept={(value) => +            doAccept(value).then(() => { +              setReviewed(value); +            }) +          } +        /> +      )} + +      <footer> +        <Button onClick={onCancel}> +          <i18n.Translate>Cancel</i18n.Translate> +        </Button> +        {!terms && ( +          <Button disabled> +            <i18n.Translate>Loading terms..</i18n.Translate> +          </Button> +        )} +        {terms && ( +          <Fragment> +            {needsReview && !reviewed && ( +              <ButtonSuccess disabled upperCased onClick={onConfirm}> +                {i18n.str`Add exchange`} +              </ButtonSuccess> +            )} +            {(terms.status === "accepted" || (needsReview && reviewed)) && ( +              <ButtonSuccess upperCased onClick={onConfirm}> +                {i18n.str`Add exchange`} +              </ButtonSuccess> +            )} +            {terms.status === "notfound" && ( +              <ButtonWarning upperCased onClick={onConfirm}> +                {i18n.str`Add exchange anyway`} +              </ButtonWarning> +            )} +          </Fragment> +        )} +      </footer> +    </Fragment> +  ); +} diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx new file mode 100644 index 000000000..10449c101 --- /dev/null +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx @@ -0,0 +1,75 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/> + */ + +import { +  canonicalizeBaseUrl, +  TalerConfigResponse, +} from "@gnu-taler/taler-util"; +import { h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { useAsyncAsHook } from "../hooks/useAsyncAsHook"; +import { queryToSlashKeys } from "../utils"; +import * as wxApi from "../wxApi"; +import { ExchangeAddConfirmPage } from "./ExchangeAddConfirm"; +import { ExchangeSetUrlPage } from "./ExchangeSetUrl"; + +interface Props { +  currency: string; +  onBack: () => void; +} + +export function ExchangeAddPage({ onBack }: Props): VNode { +  const [verifying, setVerifying] = useState< +    { url: string; config: TalerConfigResponse } | undefined +  >(undefined); + +  const knownExchangesResponse = useAsyncAsHook(wxApi.listExchanges); +  const knownExchanges = !knownExchangesResponse +    ? [] +    : knownExchangesResponse.hasError +    ? [] +    : knownExchangesResponse.response.exchanges; + +  if (!verifying) { +    return ( +      <ExchangeSetUrlPage +        onCancel={onBack} +        knownExchanges={knownExchanges} +        onVerify={(url) => queryToSlashKeys(url)} +        onConfirm={(url) => +          queryToSlashKeys<TalerConfigResponse>(url) +            .then((config) => { +              setVerifying({ url, config }); +            }) +            .catch((e) => e.message) +        } +      /> +    ); +  } +  return ( +    <ExchangeAddConfirmPage +      url={verifying.url} +      onCancel={onBack} +      onConfirm={async () => { +        await wxApi.addExchange({ +          exchangeBaseUrl: canonicalizeBaseUrl(verifying.url), +          forceUpdate: true, +        }); +        onBack(); +      }} +    /> +  ); +} diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeAddSetUrl.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeAddSetUrl.stories.tsx new file mode 100644 index 000000000..bc182cb70 --- /dev/null +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeAddSetUrl.stories.tsx @@ -0,0 +1,62 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { createExample } from "../test-utils"; +import { queryToSlashKeys } from "../utils"; +import { ExchangeSetUrlPage as TestedComponent } from "./ExchangeSetUrl"; + +export default { +  title: "wallet/exchange add/set url", +  component: TestedComponent, +  argTypes: { +    onRetry: { action: "onRetry" }, +    onDelete: { action: "onDelete" }, +    onBack: { action: "onBack" }, +  }, +}; + +export const ExpectedUSD = createExample(TestedComponent, { +  expectedCurrency: "USD", +  onVerify: queryToSlashKeys, +  knownExchanges: [], +}); + +export const ExpectedKUDOS = createExample(TestedComponent, { +  expectedCurrency: "KUDOS", +  onVerify: queryToSlashKeys, +  knownExchanges: [], +}); + +export const InitialState = createExample(TestedComponent, { +  onVerify: queryToSlashKeys, +  knownExchanges: [], +}); + +export const WithDemoAsKnownExchange = createExample(TestedComponent, { +  knownExchanges: [ +    { +      currency: "TESTKUDOS", +      exchangeBaseUrl: "https://exchange.demo.taler.net/", +      paytoUris: [], +    }, +  ], +  onVerify: queryToSlashKeys, +}); diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx new file mode 100644 index 000000000..e87a8894f --- /dev/null +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx @@ -0,0 +1,130 @@ +import { +  canonicalizeBaseUrl, +  ExchangeListItem, +  i18n, +  TalerConfigResponse, +} from "@gnu-taler/taler-util"; +import { Fragment, h } from "preact"; +import { useEffect, useState } from "preact/hooks"; +import { ErrorMessage } from "../components/ErrorMessage"; +import { +  Button, +  ButtonPrimary, +  Input, +  WarningBox, +} from "../components/styled/index"; + +export interface Props { +  initialValue?: string; +  expectedCurrency?: string; +  knownExchanges: ExchangeListItem[]; +  onCancel: () => void; +  onVerify: (s: string) => Promise<TalerConfigResponse | undefined>; +  onConfirm: (url: string) => Promise<string | undefined>; +  withError?: string; +} + +export function ExchangeSetUrlPage({ +  initialValue, +  knownExchanges, +  expectedCurrency, +  onCancel, +  onVerify, +  onConfirm, +  withError, +}: Props) { +  const [value, setValue] = useState<string>(initialValue || ""); +  const [dirty, setDirty] = useState(false); +  const [result, setResult] = useState<TalerConfigResponse | undefined>( +    undefined, +  ); +  const [error, setError] = useState<string | undefined>(withError); + +  useEffect(() => { +    try { +      const url = canonicalizeBaseUrl(value); + +      const found = +        knownExchanges.findIndex((e) => e.exchangeBaseUrl === url) !== -1; + +      if (found) { +        setError("This exchange is already known"); +        return; +      } +      onVerify(url) +        .then((r) => { +          setResult(r); +        }) +        .catch(() => { +          setResult(undefined); +        }); +      setDirty(true); +    } catch { +      setResult(undefined); +    } +  }, [value]); + +  return ( +    <Fragment> +      <section> +        {!expectedCurrency ? ( +          <h1>Add new exchange</h1> +        ) : ( +          <h2>Add exchange for {expectedCurrency}</h2> +        )} +        <ErrorMessage +          title={error && "Unable to add this exchange"} +          description={error} +        /> +        <p> +          <Input invalid={dirty && !!error}> +            <label>URL</label> +            <input +              type="text" +              placeholder="https://" +              value={value} +              onInput={(e) => setValue(e.currentTarget.value)} +            /> +          </Input> +          {result && ( +            <Fragment> +              <Input> +                <label>Version</label> +                <input type="text" disabled value={result.version} /> +              </Input> +              <Input> +                <label>Currency</label> +                <input type="text" disabled value={result.currency} /> +              </Input> +            </Fragment> +          )} +        </p> +      </section> +      {result && expectedCurrency && expectedCurrency !== result.currency && ( +        <WarningBox> +          This exchange doesn't match the expected currency{" "} +          <b>{expectedCurrency}</b> +        </WarningBox> +      )} +      <footer> +        <Button onClick={onCancel}> +          <i18n.Translate>Cancel</i18n.Translate> +        </Button> +        <ButtonPrimary +          disabled={ +            !result || +            !!error || +            (expectedCurrency !== undefined && +              expectedCurrency !== result.currency) +          } +          onClick={() => { +            const url = canonicalizeBaseUrl(value); +            return onConfirm(url).then((r) => (r ? setError(r) : undefined)); +          }} +        > +          <i18n.Translate>Next</i18n.Translate> +        </ButtonPrimary> +      </footer> +    </Fragment> +  ); +} diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx index 41852e38c..16f239674 100644 --- a/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx @@ -31,6 +31,7 @@ import {    LightText,    SmallLightText,  } from "../components/styled/index"; +import { queryToSlashConfig } from "../utils";  import * as wxApi from "../wxApi";  interface Props { @@ -38,45 +39,19 @@ interface Props {    onBack: () => void;  } -function getJsonIfOk(r: Response) { -  if (r.ok) { -    return r.json(); -  } else { -    if (r.status >= 400 && r.status < 500) { -      throw new Error(`URL may not be right: (${r.status}) ${r.statusText}`); -    } else { -      throw new Error( -        `Try another server: (${r.status}) ${ -          r.statusText || "internal server error" -        }`, -      ); -    } -  } -} -  export function ProviderAddPage({ onBack }: Props): VNode {    const [verifying, setVerifying] = useState<      | { url: string; name: string; provider: BackupBackupProviderTerms }      | undefined    >(undefined); -  async function getProviderInfo( -    url: string, -  ): Promise<BackupBackupProviderTerms> { -    return fetch(new URL("config", url).href) -      .catch((e) => { -        throw new Error(`Network error`); -      }) -      .then(getJsonIfOk); -  } -    if (!verifying) {      return (        <SetUrlView          onCancel={onBack} -        onVerify={(url) => getProviderInfo(url)} +        onVerify={(url) => queryToSlashConfig(url)}          onConfirm={(url, name) => -          getProviderInfo(url) +          queryToSlashConfig<BackupBackupProviderTerms>(url)              .then((provider) => {                setVerifying({ url, name, provider });              }) diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx index 075126dc8..f009c5ad0 100644 --- a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx @@ -3,6 +3,7 @@ import { Fragment, h, VNode } from "preact";  import { BankDetailsByPaytoType } from "../components/BankDetailsByPaytoType";  import { QR } from "../components/QR";  import { ButtonDestructive, WarningBox } from "../components/styled"; +import { amountToString } from "../utils";  export interface Props {    reservePub: string;    payto: string; @@ -29,10 +30,10 @@ export function ReserveCreated({          <h1>Exchange is ready for withdrawal!</h1>          <p>            To complete the process you need to wire{" "} -          <b>{Amounts.stringify(amount)}</b> to the exchange bank account +          <b>{amountToString(amount)}</b> to the exchange bank account          </p>          <BankDetailsByPaytoType -          amount={Amounts.stringify(amount)} +          amount={amountToString(amount)}            exchangeBaseUrl={exchangeBaseUrl}            payto={paytoURI}            subject={reservePub} diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.tsx index 586d7b53e..5f1cd89d3 100644 --- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx @@ -17,12 +17,13 @@  import { ExchangeListItem, i18n } from "@gnu-taler/taler-util";  import { Fragment, h, VNode } from "preact";  import { Checkbox } from "../components/Checkbox"; -import { ButtonPrimary } from "../components/styled"; +import { LinkPrimary } from "../components/styled";  import { useDevContext } from "../context/devContext";  import { useAsyncAsHook } from "../hooks/useAsyncAsHook";  import { useBackupDeviceName } from "../hooks/useBackupDeviceName";  import { useExtendedPermissions } from "../hooks/useExtendedPermissions";  import { useLang } from "../hooks/useLang"; +import { Pages } from "../NavigationBar";  // import { strings as messages } from "../i18n/strings";  import * as wxApi from "../wxApi"; @@ -112,7 +113,7 @@ export function SettingsView({          )}          <div style={{ display: "flex", justifyContent: "space-between" }}>            <div /> -          <ButtonPrimary>Manage exchange</ButtonPrimary> +          <LinkPrimary href={Pages.exchange_add}>Add an exchange</LinkPrimary>          </div>          <h2> diff --git a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx index a17550ff9..73000c9ae 100644 --- a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx +++ b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx @@ -44,6 +44,7 @@ import { ManualWithdrawPage } from "./wallet/ManualWithdrawPage";  import { WalletBox } from "./components/styled";  import { ProviderDetailPage } from "./wallet/ProviderDetailPage";  import { ProviderAddPage } from "./wallet/ProviderAddPage"; +import { ExchangeAddPage } from "./wallet/ExchangeAddPage";  function main(): void {    try { @@ -132,6 +133,14 @@ function Application(): VNode {            />            <Route +            path={Pages.exchange_add} +            component={withLogoAndNavBar(ExchangeAddPage)} +            onBack={() => { +              route(Pages.balance); +            }} +          /> + +          <Route              path={Pages.manual_withdraw}              component={withLogoAndNavBar(ManualWithdrawPage)}            /> | 
