online-accounts-api-0.1+16.04.20160212/0000755000015600001650000000000012657307121017564 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/doc/0000755000015600001650000000000012657307121020331 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/doc/ubuntu-onlineaccounts2.qdocconf0000644000015600001650000000130312657306726026504 0ustar pbuserpbgroup00000000000000project = UbuntuOnlineAccounts2 description = Ubuntu.OnlineAccounts 2.0 module documentation sourcedirs = ./ ../src/lib/Ubuntu/OnlineAccounts.2/ sources.fileextensions = "*.qdoc *.cpp" outputdir = html outputformats = HTML version = 0.2 syntaxhightlighting = true sourceencoding = UTF-8 outputencoding = UTF-8 HTML.nonavigationbar = "true" HTML.stylesheets = \ css/base.css \ css/qtquick.css \ css/reset.css \ css/scratch.css HTML.headerstyles = \ "\n" \ "\n" \ "\n" online-accounts-api-0.1+16.04.20160212/doc/css/0000755000015600001650000000000012657307121021121 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/doc/css/base.css0000644000015600001650000002707612657306726022573 0ustar pbuserpbgroup00000000000000/** * Ubuntu Developer base stylesheet * * A base stylesheet containing site-wide styles * * @project Ubuntu Developer * @version 1.0 * @author Canonical Web Team: Steve Edwards * @copyright 2011 Canonical Ltd. */ /** * @section Global */ body { font-family: 'Ubuntu', 'Ubuntu Beta', UbuntuBeta, Ubuntu, 'Bitstream Vera Sans', 'DejaVu Sans', Tahoma, sans-serif; font-size: 13px; line-height: 1.4; color: #333; } a { color: #dd4814; text-decoration: none; outline: 0; } p, dl { margin-bottom: 10px; } strong { font-weight: bold; } em { font-style: italic; } code{ padding: 10px; font-family: 'Ubuntu Mono', 'Consolas', 'Monaco', 'DejaVu Sans Mono', Courier, monospace; background-color: #fdf6f2; display: inline-block; margin-bottom: 10px; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } h1 { font-size: 36px; line-height: 1.1; margin-bottom: 20px; } article h1, h2 { font-size: 24px; line-height: 1.2; margin-bottom: 14px; } h3 { font-size: 16px; line-height: 1.3; margin-bottom: 8px; } h4 { font-weight: bold; } time { color:#999; } /** * @section Structure */ .header-login, .header-navigation div, .header-content div { margin: 0 auto; width: 940px; } .header-content h1{ background-color:#ffffff; display:inline-block; } .header-content h2{ background-color:#ffffff; display:table; } .header-login ul { margin: 4px 0; float: right; } .header-login li { margin-right: 10px; float: left; } .header-login a { color: #333; } .header-navigation { border-top: 2px solid #dd4814; border-bottom: 2px solid #dd4814; background-color: #fff; height: 54px; clear: right; overflow: hidden; } .header-navigation nav ul { border-right: 1px solid #dd4814; float: right; } .header-navigation nav li { border-left: 1px solid #dd4814; float: left; height: 54px; } .header-navigation nav a { padding: 18px 14px 0; font-size: 14px; display: block; height: 36px; } .header-navigation nav a:hover { background-color: #fcece7; } .header-navigation nav .current_page_item a, .header-navigation nav .current_page_parent a, .header-navigation nav .current_page_ancestor a { background-color: #dd4814; color: #fff; } .header-navigation input { margin: 12px 10px 0 10px; padding: 5px; border-top: 1px solid #a1a1a1; border-right: 1px solid #e0e0e0; border-bottom: 1px solid #fff; border-left: 1px solid #e0e0e0; width: 90px; font-style: italic; color: #ccc; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; -moz-box-shadow: inset 0 1px 1px #e0e0e0; -webkit-box-shadow: inset 0 1px 1px #e0e0e0; box-shadow: inset 0 1px 1px #e0e0e0; } .header-navigation h2 { margin: 18px 0 0 6px; text-transform: lowercase; font-size: 22px; color: #dd4814; float: left; } .header-navigation .logo-ubuntu { margin-top: 12px; float: left; } .header-content .header-navigation-secondary { margin-bottom: 40px; padding: 0; position: relative; z-index: 2; } .header-navigation-secondary div { padding: 0; border: 2px solid #dd4814; -moz-border-radius: 0px 0px 4px 4px; -webkit-border-radius: 0px 0px 4px 4px; border-radius: 0px 0px 4px 4px; background: #fff; border-top: 0px; width: 936px; } .header-navigation-secondary nav li { float: left; } .header-navigation-secondary nav li a { color: #333; display: block; height: 25px; padding: 8px 8px 0; } .header-navigation-secondary nav li:hover, .header-navigation-secondary nav .current_page_item a { background: url("../img/sec-nav-hover.gif"); } .header-content { padding-bottom: 30px; border-bottom: 1px solid #e0e0e0; -moz-box-shadow: 0 1px 3px #e0e0e0; -webkit-box-shadow: 0 1px 3px #e0e0e0; box-shadow: 0 1px 3px #e0e0e0; margin-bottom: 3px; position: relative; overflow: hidden; } footer { padding: 10px 10px 40px 10px; position: relative; -moz-border-radius: 0 0 4px 4px; -webkit-border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px; font-size: 12px; background: url("../img/background-footer.png") repeat scroll 0 0 #f7f6f5; } footer div { margin: 0 auto; padding: 0 10px; width: 940px; } footer a { color: #000; } footer nav ul { margin: 10px 17px 30px 0; width: 172px; display: inline-block; vertical-align: top; height: auto; zoom: 1; *display: inline; } footer nav ul.last { margin-right: 0; } footer nav li { margin-bottom: 8px; } footer nav li:first-child { font-weight: bold; } footer p { margin-bottom: 0; } #content { padding-top: 35px; } .arrow-nav { display: none; position: absolute; top: -1px; z-index: 3; } .shadow { margin: 30px 0 3px 0; border-bottom: 1px solid #e0e0e0; -moz-box-shadow: 0 2px 3px #e0e0e0; -webkit-box-shadow: 0 2px 3px #e0e0e0; box-shadow: 0 2px 3px #e0e0e0; height: 3px; } /** * @section Site-wide */ #content h2{ font-size:24px; } .box-orange { padding: 10px; border: 3px solid #dd4814; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } .box-orange .link-action-small { float: right; margin: 0 0 0 20px; } .link-bug { margin-left: 10px; color: #999; } .link-action { float: left; margin-bottom: 20px; padding: 8px 12px; display: block; background-color: #dd4814; color: #fff; -moz-border-radius: 20px; -webkit-border-radius: 20px; border-radius: 20px; font-size: 16px; line-height: 1.3; border-top: 3px solid #e6633a; border-bottom: 3px solid #c03d14; } .link-action2 { float: left; display: block; color: #fff; font-size: 16px; line-height: 1.3; } .link-action2 span{ display:block; float:left; } .link-action2 .cta-left{ background:url(../img/button-cta-left.png) no-repeat; width:22px; height:48px; } .link-action2 .cta-center{ background:url(../img/button-cta-slice.png) repeat-x; line-height:45px; height:48px; } .link-action2 .cta-right{ background:url(../img/button-cta-right.png) no-repeat; width:22px; height:48px; } .link-action-small { float: left; display: block; color: #fff; font-size: 16px; } .link-action-small span{ display:block; float:left; height:42px; } .link-action-small .cta-left{ background:url(../img/button-cta-left-small.png) no-repeat; width:19px; } .link-action-small .cta-center{ background:url(../img/button-cta-slice-small.png) repeat-x; line-height:42px; } .link-action-small .cta-right{ background:url(../img/button-cta-right-small.png) no-repeat; width:19px; } .link-action:active { position: relative; top: 1px; } .link-action2:active { position: relative; top: 1px; } .link-action-small:active { position: relative; top: 1px; } .list-bullets li { margin-bottom: 10px; list-style: disc; list-style-position: inside; } .box { margin-bottom: 30px; padding: 15px; border: 1px solid #aea79f; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } .box-padded { margin-bottom: 30px; padding: 5px; border: 2px solid #aea79f; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; background: url("../img/pattern-featured.gif") repeat scroll 0 0 #ebe9e7; overflow: hidden; } .box-padded h3 { margin: 5px 0 10px 5px; } .box-padded div { padding: 10px; border: 1px solid #aea79f; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; background-color: #fff; overflow: hidden; } .box-padded li { padding: 0 10px; float: left; width: 211px; border-right: 1px dotted #aea79f; } .box-padded li.first { padding: 0; margin-bottom: 0; } .box-padded li.last { border: 0; width: 217px; } .box-padded img { margin: 0 10px 50px 0; float: left; -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } .box-clear { margin-bottom: 40px; } .box-clear .grid-4.first { margin-right: 15px; padding-right: 15px; } .box-clear .grid-4 { margin-left: 0; margin-right: 10px; padding-right: 10px; width: 298px; } .box-clear time { display: block; border-bottom: 1px dotted #aea79f; padding-bottom: 10px; margin-bottom: 10px; } .box-clear div.first { border-right: 1px dotted #aea79f; } .box-clear a { display: block; } .box-clear .rss { background: url("../img/rss.jpg") no-repeat scroll 0 center; padding-left: 20px; } .box-clear .location { display: block; margin-bottom: 1px; } .box-clear .last { margin: 0; padding-right: 0; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; width: 293px; } /* Widgets */ .ui-state-focus { outline: none; } .ui-accordion { border-bottom: 1px dotted #aea79f; } .ui-accordion a { display: block; } .ui-accordion h3 { margin-bottom: 0; border-top: 1px dotted #aea79f; position: relative; font-size: 13px; font-weight: bold; } .ui-accordion h3 a { padding: 10px 0; color: #333; } .ui-accordion h4 { margin-bottom: 5px; } .ui-accordion div fieldset { padding-bottom: 5px; } .ui-accordion div li, .ui-accordion div input { margin-bottom: 10px; } .ui-accordion .ui-icon { position: absolute; top: 15px; right: 0; display: block; width: 8px; height: 8px; background: url("../img/icon-accordion-inactive.png") 0 0 no-repeat transparent; } .ui-accordion .ui-state-active .ui-icon { background-image: url("../img/icon-accordion-active.png"); } .ui-accordion .current_page_item a { color: #333; } .container-tweet { -moz-border-radius: 4px 4px 4px 4px; -webkit-border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px; padding: 10px 10px 10px; background-color: #f7f7f7; } .container-tweet .tweet-follow { margin-top: 10px; margin-bottom: -10px; padding-left: 55px; padding-bottom: 6px; background: url("../img/tweet-follow.png") 0 5px no-repeat; display: block; } .container-tweet .tweet-follow span { font-size: 16px; font-weight: bold; line-height: 1.2; display: block; } .tweet a { display: inline; } .tweet .tweet_text { padding: 10px; background-color: #fff; -moz-border-radius: 4px 4px 4px 4px; -webkit-border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px; border: 1px solid #dd4814; font-size: 16px; display: block; clear: both; } .tweet.tweet-small .tweet_text { font-size: inherit; } .tweet .tweet_text a { color: #333; } .tweet .tweet_time, .tweet .tweet_user_and_time { padding: 15px 0 10px 0; position: relative; top: -2px; background: url("../img/tweet-arrow.png") no-repeat; display: block; } .tweet .tweet_odd .tweet_time, .tweet .tweet_odd .tweet_user_and_time { background-position: right 0; float: right; } .tweet .tweet_even .tweet_time, .tweet .tweet_even .tweet_user_and_time { background-position: left 0; float: left; } /* Search */ #content .list-search li { list-style-type:none; border:0px; margin-bottom: 15px; padding-top: 15px; } /* Blog */ .blog-article #nav-single { margin-top: 30px; margin-bottom: 30px; } .blog-article #nav-single .nav-next { float: right; } .blog-article article header .entry-meta { margin-bottom: 20px; } .blog-article article .entry-meta { color: #999; } .blog-article #respond form input[type="submit"] { float: left; cursor: pointer; margin-bottom: 20px; padding: 8px 12px; display: block; background-color: #dd4814; color: #fff; -moz-border-radius: 20px; -webkit-border-radius: 20px; border-radius: 20px; font-size: 16px; line-height: 1.3; border-top: 3px solid #e6633a; border-left: 3px solid #e6633a; border-right: 3px solid #e6633a; border-bottom: 3px solid #c03d14; } .blog-article #respond form input[type="submit"]:active { position: relative; top: 1px; } .alignnone{ float:left; margin:10px 20px 10px 0; } .alignleft{ float:left; margin:10px 20px 10px 0; } .alignright{ float:right; margin:10px 0 10px 20px; } .aligncenter{ float:left; margin:10px 20px 10px 0; } .entry-content h2, .entry-content h3{ margin-top:20px; } .entry-content ul li{ list-style-type: circle; margin-left:16px; } .entry-content hr{ border:none; border-top: 1px dotted #AEA79F; } online-accounts-api-0.1+16.04.20160212/doc/css/scratch.css0000644000015600001650000000350612657306726023300 0ustar pbuserpbgroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ body { margin: 0; } div.toc ul { padding: 0; } div.toc li { margin-bottom: 3px; } h1.title { font-size: 36px; line-height: 1.1; font-weight: normal; } h0, h2 { font-size: 24px; line-height: 1.2; margin: 14px 0; font-weight: normal; display: block; } a:hover { color: #dd4814; text-decoration: underline; outline: 0; } table, pre { border-radius: 0; white-space: pre-wrap; } .annotated td { padding: 0.8em 1em 0.3em; } .wrapper { width: 940px; margin: 0 auto; } .main-content { width: 668px; position: relative; left: 270px; } .title { margin-left: -270px; margin-top: 30px; margin-bottom: 50px; } .toc { margin-left: -270px; font-size: 100%; margin-bottom: 40px; padding: 0; z-index: 2; position: absolute; top: 100px; width: 250px; } .breadcrumb { position: relative; left: -270px; top: 30px; width: auto; padding-bottom: 30px; margin-bottom: 30px; float:left; } .breadcrumb li { float: left; margin-right: 8px; } .breadcrumb a:link, .breadcrumb a:visited { color: #AEA79F; } .breadcrumb a:after { content: '\0000a0\0000a0 >'; } .title { margin-top: 50px; clear:both; } .breadcrumb + .toc { top: 170px; } .breadcrumb p { display: inline; } online-accounts-api-0.1+16.04.20160212/doc/css/custom.css0000644000015600001650000000016412657306726023160 0ustar pbuserpbgroup00000000000000li#buildversion { display: none; } div.toc { display: none; } span.type a:visited { color: #dd4814; } online-accounts-api-0.1+16.04.20160212/doc/css/breadcrumbs.js0000644000015600001650000000141612657306726023764 0ustar pbuserpbgroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ $(document).ready(function(){ var ul = $("ul.breadcrumb"); var li = ul.children("li:has(a)").remove(); ul.prepend(li); }); online-accounts-api-0.1+16.04.20160212/doc/css/reset.css0000644000015600001650000000153312657306726022771 0ustar pbuserpbgroup00000000000000/* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html version: 3.3.0 build: 3167 */ html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}online-accounts-api-0.1+16.04.20160212/doc/css/qtquick.css0000644000015600001650000003316012657306726023331 0ustar pbuserpbgroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ @media screen { /* basic elements */ html { color: #000000; background: #FFFFFF; } table { border-collapse: collapse; border-spacing: 0; } fieldset, img { border: 0; max-width:100%; } address, caption, cite, code, dfn, em, strong, th, var, optgroup { font-style: inherit; font-weight: inherit; } del, ins { text-decoration: none; } ol li { list-style: decimal; } ul li { list-style: none; } caption, th { text-align: left; } h1.title { font-weight: bold; font-size: 150%; } h0 { font-weight: bold; font-size: 130%; } h1, h2, h3, h4, h5, h6 { font-size: 100%; } q:before, q:after { content: ''; } abbr, acronym { border: 0; font-variant: normal; } sup, sub { vertical-align: baseline; } tt, .qmlreadonly span, .qmldefault span { word-spacing:0.5em; } legend { color: #000000; } strong { font-weight: bold; } em { font-style: italic; } body { margin: 0 1.5em 0 1.5em; font-family: ubuntu; line-height: normal } a { color: #00732F; text-decoration: none; } hr { background-color: #E6E6E6; border: 1px solid #E6E6E6; height: 1px; width: 100%; text-align: left; margin: 1.5em 0 1.5em 0; } pre { border: 1px solid #DDDDDD; -moz-border-radius: 0.7em 0.7em 0.7em 0.7em; -webkit-border-radius: 0.7em 0.7em 0.7em 0.7em; border-radius: 0.7em 0.7em 0.7em 0.7em; padding: 1em 1em 1em 1em; overflow-x: auto; } table, pre { -moz-border-radius: 0.7em 0.7em 0.7em 0.7em; -webkit-border-radius: 0.7em 0.7em 0.7em 0.7em; border-radius: 0.7em 0.7em 0.7em 0.7em; background-color: #F6F6F6; border: 1px solid #E6E6E6; border-collapse: separate; margin-bottom: 2.5em; } pre { font-size: 90%; display: block; overflow:hidden; } thead { margin-top: 0.5em; font-weight: bold } th { padding: 0.5em 1.5em 0.5em 1em; background-color: #E1E1E1; border-left: 1px solid #E6E6E6; } td { padding: 0.25em 1.5em 0.25em 1em; } td.rightAlign { padding: 0.25em 0.5em 0.25em 1em; } table tr.odd { border-left: 1px solid #E6E6E6; background-color: #F6F6F6; color: black; } table tr.even { border-left: 1px solid #E6E6E6; background-color: #ffffff; color: #202020; } div.float-left { float: left; margin-right: 2em } div.float-right { float: right; margin-left: 2em } span.comment { color: #008B00; } span.string, span.char { color: #000084; } span.number { color: #a46200; } span.operator { color: #202020; } span.keyword { color: #840000; } span.name { color: black } span.type { font-weight: bold } span.type a:visited { color: #0F5300; } span.preprocessor { color: #404040 } /* end basic elements */ /* font style elements */ .heading { font-weight: bold; font-size: 125%; } .subtitle { font-size: 110% } .small-subtitle { font-size: 100% } .red { color:red; } /* end font style elements */ /* global settings*/ .header, .footer { display: block; clear: both; overflow: hidden; } /* end global settings*/ /* header elements */ .header .qtref { color: #00732F; font-weight: bold; font-size: 130%; } .header .content { margin-left: 5px; margin-top: 5px; margin-bottom: 0.5em; } .header .breadcrumb { font-size: 90%; padding: 0.5em 0 0.5em 1em; margin: 0; background-color: #fafafa; height: 1.35em; border-bottom: 1px solid #d1d1d1; } .header .breadcrumb ul { margin: 0; padding: 0; } .header .content { word-wrap: break-word; } .header .breadcrumb ul li { float: left; background: url(../images/breadcrumb.png) no-repeat 0 3px; padding-left: 1.5em; margin-left: 1.5em; } .header .breadcrumb ul li.last { font-weight: normal; } .header .breadcrumb ul li a { color: #00732F; } .header .breadcrumb ul li.first { background-image: none; padding-left: 0; margin-left: 0; } .header .content ol li { background: none; margin-bottom: 1.0em; margin-left: 1.2em; padding-left: 0 } .header .content li { background: url(../images/bullet_sq.png) no-repeat 0 5px; margin-bottom: 1em; padding-left: 1.2em; } /* end header elements */ /* content elements */ .content h1 { font-weight: bold; font-size: 130% } .content h2 { font-weight: bold; font-size: 120%; width: 100%; } .content h3 { font-weight: bold; font-size: 110%; width: 100%; } .content table p { margin: 0 } .content ul { padding-left: 2.5em; } .content li { padding-top: 0.25em; padding-bottom: 0.25em; } .content ul img { vertical-align: middle; } .content a:visited { color: #4c0033; text-decoration: none; } .content a:visited:hover { color: #4c0033; text-decoration: underline; } a:hover { color: #4c0033; text-decoration: underline; } descr p a { text-decoration: underline; } .descr p a:visited { text-decoration: underline; } .alphaChar{ width:95%; background-color:#F6F6F6; border:1px solid #E6E6E6; -moz-border-radius: 7px 7px 7px 7px; border-radius: 7px 7px 7px 7px; -webkit-border-radius: 7px 7px 7px 7px; font-size:12pt; padding-left:10px; margin-top:10px; margin-bottom:10px; } .flowList{ /*vertical-align:top;*/ /*margin:20px auto;*/ column-count:3; -webkit-column-count:3; -moz-column-count:3; /* column-width:100%; -webkit-column-width:200px; -col-column-width:200px; */ column-gap:41px; -webkit-column-gap:41px; -moz-column-gap:41px; column-rule: 1px dashed #ccc; -webkit-column-rule: 1px dashed #ccc; -moz-column-rule: 1px dashed #ccc; } .flowList dl{ } .flowList dd{ /*display:inline-block;*/ margin-left:10px; min-width:250px; line-height: 1.5; min-width:100%; min-height:15px; } .flowList dd a{ } .mainContent { padding-left:5px; } .content .flowList p{ padding:0px; } .content .alignedsummary { margin: 15px; } .qmltype { text-align: center; font-size: 120%; } .qmlreadonly { padding-left: 5px; float: right; color: #254117; } .qmldefault { padding-left: 5px; float: right; color: red; } .qmldoc { } .generic .alphaChar{ margin-top:5px; } .generic .odd .alphaChar{ background-color: #F6F6F6; } .generic .even .alphaChar{ background-color: #FFFFFF; } .memItemRight{ padding: 0.25em 1.5em 0.25em 0; } .highlightedCode { margin: 1.0em; } .annotated td { padding: 0.25em 0.5em 0.25em 0.5em; } .toc { font-size: 80% } .header .content .toc ul { padding-left: 0px; } .content .toc h3 { border-bottom: 0px; margin-top: 0px; } .content .toc h3 a:hover { color: #00732F; text-decoration: none; } .content .toc .level2 { margin-left: 1.5em; } .content .toc .level3 { margin-left: 3.0em; } .content ul li { background: url(../images/bullet_sq.png) no-repeat 0 0.7em; padding-left: 1em } .content .toc li { background: url(../images/bullet_dn.png) no-repeat 0 5px; padding-left: 1em } .relpage { -moz-border-radius: 7px 7px 7px 7px; -webkit-border-radius: 7px 7px 7px 7px; border-radius: 7px 7px 7px 7px; border: 1px solid #DDDDDD; padding: 25px 25px; clear: both; } .relpage ul { float: none; padding: 1.5em; } h3.fn, span.fn { -moz-border-radius:7px 7px 7px 7px; -webkit-border-radius:7px 7px 7px 7px; border-radius:7px 7px 7px 7px; background-color: #F6F6F6; border-width: 1px; border-style: solid; border-color: #E6E6E6; font-weight: bold; word-spacing:3px; padding:3px 5px; } .functionIndex { font-size:12pt; word-spacing:10px; margin-bottom:10px; background-color: #F6F6F6; border-width: 1px; border-style: solid; border-color: #E6E6E6; -moz-border-radius: 7px 7px 7px 7px; -webkit-border-radius: 7px 7px 7px 7px; border-radius: 7px 7px 7px 7px; width:100%; } .centerAlign { text-align:center; } .rightAlign { text-align:right; } .leftAlign { text-align:left; } .topAlign{ vertical-align:top } .functionIndex a{ display:inline-block; } /* end content elements */ /* footer elements */ .footer { color: #393735; font-size: 0.75em; text-align: center; padding-top: 1.5em; padding-bottom: 1em; background-color: #E6E7E8; margin: 0; } .footer p { margin: 0.25em } .small { font-size: 0.5em; } /* end footer elements */ .item { float: left; position: relative; width: 100%; overflow: hidden; } .item .primary { margin-right: 220px; position: relative; } .item hr { margin-left: -220px; } .item .secondary { float: right; width: 200px; position: relative; } .item .cols { clear: both; display: block; } .item .cols .col { float: left; margin-left: 1.5%; } .item .cols .col.first { margin-left: 0; } .item .cols.two .col { width: 45%; } .item .box { margin: 0 0 10px 0; } .item .box h3 { margin: 0 0 10px 0; } .cols.unclear { clear:none; } } /* end of screen media */ /* start of print media */ @media print { input, textarea, .header, .footer, .toolbar, .feedback, .wrapper .hd, .wrapper .bd .sidebar, .wrapper .ft, #feedbackBox, #blurpage, .toc, .breadcrumb, .toolbar, .floatingResult { display: none; background: none; } .content { background: none; display: block; width: 100%; margin: 0; float: none; } } /* end of print media */ /* modify the TOC layouts */ div.toc ul { padding-left: 20px; } div.toc li { padding-left: 4px; } /* Remove the border around images*/ a img { border:none; } /*Add styling to the front pages*/ .threecolumn_area { padding-top: 20px; padding-bottom: 20px; } .threecolumn_piece { display: inline-block; margin-left: 78px; margin-top: 8px; padding: 0; vertical-align: top; width: 25.5%; } div.threecolumn_piece ul { list-style-type: none; padding-left: 0px; margin-top: 2px; } div.threecolumn_piece p { margin-bottom: 7px; color: #5C626E; text-decoration: none; font-weight: bold; } div.threecolumn_piece li { padding-left: 0px; margin-bottom: 5px; } div.threecolumn_piece a { font-weight: normal; } /* Add style to guide page*/ .fourcolumn_area { padding-top: 20px; padding-bottom: 20px; } .fourcolumn_piece { display: inline-block; margin-left: 35px; margin-top: 8px; padding: 0; vertical-align: top; width: 21.3%; } div.fourcolumn_piece ul { list-style-type: none; padding-left: 0px; margin-top: 2px; } div.fourcolumn_piece p { margin-bottom: 7px; color: #40444D; text-decoration: none; font-weight: bold; } div.fourcolumn_piece li { padding-left: 0px; margin-bottom: 5px; } div.fourcolumn_piece a { font-weight: normal; } online-accounts-api-0.1+16.04.20160212/doc/CMakeLists.txt0000644000015600001650000000106712657306726023107 0ustar pbuserpbgroup00000000000000project(OnlineAccountsQML-doc) find_program(QDOC_EXECUTABLE qdoc) if(QDOC_EXECUTABLE STREQUAL "QDOC_EXECUTABLE-NOTFOUND") message(WARNING "qdoc not found, documentation cannot be built") else() add_custom_target(doc ALL COMMAND ${QDOC_EXECUTABLE} -outputdir ${CMAKE_CURRENT_BINARY_DIR}/html ${CMAKE_CURRENT_SOURCE_DIR}/ubuntu-onlineaccounts2.qdocconf) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${CMAKE_INSTALL_DATADIR}/doc/ubuntu-onlineaccounts2) endif() online-accounts-api-0.1+16.04.20160212/cmake/0000755000015600001650000000000012657307121020644 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/cmake/EnableCoverageReport.cmake0000644000015600001650000001641412657306726025724 0ustar pbuserpbgroup00000000000000# - Creates a special coverage build type and target on GCC. # # Defines a function ENABLE_COVERAGE_REPORT which generates the coverage target # for selected targets. Optional arguments to this function are used to filter # unwanted results using globbing expressions. Moreover targets with tests for # the source code can be specified to trigger regenerating the report if the # test has changed # # ENABLE_COVERAGE_REPORT(TARGETS target... [FILTER filter...] [TESTS test targets...]) # # To generate a coverage report first build the project with # CMAKE_BUILD_TYPE=coverage, then call make test and afterwards make coverage. # # The coverage report is based on gcov. Depending on the availability of lcov # a HTML report will be generated and/or an XML report of gcovr is found. # The generated coverage target executes all found solutions. Special targets # exist to create e.g. only the xml report: coverage-xml. # # Copyright (C) 2010 by Johannes Wienke # # This program 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 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # INCLUDE(ParseArguments) FIND_PACKAGE(Lcov) FIND_PACKAGE(gcovr) FUNCTION(ENABLE_COVERAGE_REPORT) # argument parsing PARSE_ARGUMENTS(ARG "FILTER;TARGETS;TESTS" "" ${ARGN}) SET(COVERAGE_RAW_FILE "${CMAKE_BINARY_DIR}/coverage.raw.info") SET(COVERAGE_FILTERED_FILE "${CMAKE_BINARY_DIR}/coverage.info") SET(COVERAGE_REPORT_DIR "${CMAKE_BINARY_DIR}/coveragereport") SET(COVERAGE_XML_FILE "${CMAKE_BINARY_DIR}/coverage.xml") SET(COVERAGE_XML_COMMAND_FILE "${CMAKE_BINARY_DIR}/coverage-xml.cmake") # decide if there is any tool to create coverage data SET(TOOL_FOUND FALSE) IF(LCOV_FOUND OR GCOVR_FOUND) SET(TOOL_FOUND TRUE) ENDIF() IF(NOT TOOL_FOUND) MESSAGE(STATUS "Cannot enable coverage targets because neither lcov nor gcovr are found.") ENDIF() STRING(TOLOWER "${CMAKE_BUILD_TYPE}" COVERAGE_BUILD_TYPE) IF(CMAKE_COMPILER_IS_GNUCXX AND TOOL_FOUND AND "${COVERAGE_BUILD_TYPE}" MATCHES "coverage") MESSAGE(STATUS "Coverage support enabled for targets: ${ARG_TARGETS}") # create coverage build type SET(CMAKE_CXX_FLAGS_COVERAGE ${CMAKE_CXX_FLAGS_DEBUG} PARENT_SCOPE) SET(CMAKE_C_FLAGS_COVERAGE ${CMAKE_C_FLAGS_DEBUG} PARENT_SCOPE) SET(CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES} coverage PARENT_SCOPE) # instrument targets SET_TARGET_PROPERTIES(${ARG_TARGETS} PROPERTIES COMPILE_FLAGS --coverage LINK_FLAGS --coverage) # html report IF (LCOV_FOUND) MESSAGE(STATUS "Enabling HTML coverage report") # set up coverage target ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_RAW_FILE} COMMAND ${LCOV_EXECUTABLE} -c -d ${CMAKE_BINARY_DIR} -o ${COVERAGE_RAW_FILE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Collecting coverage data" DEPENDS ${ARG_TARGETS} ${ARG_TESTS} VERBATIM) # filter unwanted stuff LIST(LENGTH ARG_FILTER FILTER_LENGTH) IF(${FILTER_LENGTH} GREATER 0) SET(FILTER COMMAND ${LCOV_EXECUTABLE}) FOREACH(F ${ARG_FILTER}) SET(FILTER ${FILTER} -r ${COVERAGE_FILTERED_FILE} ${F}) ENDFOREACH() SET(FILTER ${FILTER} -o ${COVERAGE_FILTERED_FILE}) ELSE() SET(FILTER "") ENDIF() ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_FILTERED_FILE} COMMAND ${LCOV_EXECUTABLE} -e ${COVERAGE_RAW_FILE} "${CMAKE_SOURCE_DIR}*" -o ${COVERAGE_FILTERED_FILE} ${FILTER} DEPENDS ${COVERAGE_RAW_FILE} COMMENT "Filtering recorded coverage data for project-relevant entries" VERBATIM) ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_REPORT_DIR} COMMAND ${CMAKE_COMMAND} -E make_directory ${COVERAGE_REPORT_DIR} COMMAND ${GENHTML_EXECUTABLE} --legend --show-details -t "${PROJECT_NAME} test coverage" -o ${COVERAGE_REPORT_DIR} ${COVERAGE_FILTERED_FILE} DEPENDS ${COVERAGE_FILTERED_FILE} COMMENT "Generating HTML coverage report in ${COVERAGE_REPORT_DIR}" VERBATIM) ADD_CUSTOM_TARGET(coverage-html DEPENDS ${COVERAGE_REPORT_DIR}) ENDIF() # xml coverage report IF(GCOVR_FOUND) MESSAGE(STATUS "Enabling XML coverage report") # filter unwanted stuff SET(GCOV_FILTER "") LIST(LENGTH ARG_FILTER FILTER_LENGTH) IF(${FILTER_LENGTH} GREATER 0) FOREACH(F ${ARG_FILTER}) SET(GCOV_FILTER "${GCOV_FILTER} -e \"${F}\"") ENDFOREACH() ENDIF() # gcovr cannot write directly to a file so the execution needs to # be wrapped in a cmake file that generates the file output FILE(WRITE ${COVERAGE_XML_COMMAND_FILE} "SET(ENV{LANG} en)\n") FILE(APPEND ${COVERAGE_XML_COMMAND_FILE} "EXECUTE_PROCESS(COMMAND \"${GCOVR_EXECUTABLE}\" -x -r \"${CMAKE_SOURCE_DIR}\" ${GCOV_FILTER} OUTPUT_FILE \"${COVERAGE_XML_FILE}\" WORKING_DIRECTORY \"${CMAKE_BINARY_DIR}\")\n") ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_XML_FILE} COMMAND ${CMAKE_COMMAND} ARGS -P ${COVERAGE_XML_COMMAND_FILE} COMMENT "Generating coverage XML report" VERBATIM) ADD_CUSTOM_TARGET(coverage-xml DEPENDS ${COVERAGE_XML_FILE}) ENDIF() # provide a global coverage target executing both steps if available SET(GLOBAL_DEPENDS "") IF(LCOV_FOUND) LIST(APPEND GLOBAL_DEPENDS ${COVERAGE_REPORT_DIR}) ENDIF() IF(GCOVR_FOUND) LIST(APPEND GLOBAL_DEPENDS ${COVERAGE_XML_FILE}) ENDIF() IF(LCOV_FOUND OR GCOVR_FOUND) ADD_CUSTOM_TARGET(coverage DEPENDS ${GLOBAL_DEPENDS}) ENDIF() ENDIF() # This gets rid of any stale .gcda files. Run this if a running a binary causes lots of messages about # about a "merge mismatch for summaries". ADD_CUSTOM_TARGET(clean-coverage COMMAND find ${CMAKE_BINARY_DIR} -name '*.gcda' | xargs rm -f) ENDFUNCTION() online-accounts-api-0.1+16.04.20160212/cmake/Findgcovr.cmake0000644000015600001650000000170212657306726023601 0ustar pbuserpbgroup00000000000000# - Find gcovr scrip # Will define: # # GCOVR_EXECUTABLE - the gcovr script # # Uses: # # GCOVR_ROOT - root to search for the script # # Copyright (C) 2011 by Johannes Wienke # # This program 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 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # INCLUDE(FindPackageHandleStandardArgs) FIND_PROGRAM(GCOVR_EXECUTABLE gcovr HINTS ${GCOVR_ROOT} "${GCOVR_ROOT}/bin") FIND_PACKAGE_HANDLE_STANDARD_ARGS(gcovr DEFAULT_MSG GCOVR_EXECUTABLE) # only visible in advanced view MARK_AS_ADVANCED(GCOVR_EXECUTABLE) online-accounts-api-0.1+16.04.20160212/cmake/ParseArguments.cmake0000644000015600001650000000340612657306726024623 0ustar pbuserpbgroup00000000000000# Parse arguments passed to a function into several lists separated by # upper-case identifiers and options that do not have an associated list e.g.: # # SET(arguments # hello OPTION3 world # LIST3 foo bar # OPTION2 # LIST1 fuz baz # ) # PARSE_ARGUMENTS(ARG "LIST1;LIST2;LIST3" "OPTION1;OPTION2;OPTION3" ${arguments}) # # results in 7 distinct variables: # * ARG_DEFAULT_ARGS: hello;world # * ARG_LIST1: fuz;baz # * ARG_LIST2: # * ARG_LIST3: foo;bar # * ARG_OPTION1: FALSE # * ARG_OPTION2: TRUE # * ARG_OPTION3: TRUE # # taken from http://www.cmake.org/Wiki/CMakeMacroParseArguments MACRO(PARSE_ARGUMENTS prefix arg_names option_names) SET(DEFAULT_ARGS) FOREACH(arg_name ${arg_names}) SET(${prefix}_${arg_name}) ENDFOREACH(arg_name) FOREACH(option ${option_names}) SET(${prefix}_${option} FALSE) ENDFOREACH(option) SET(current_arg_name DEFAULT_ARGS) SET(current_arg_list) FOREACH(arg ${ARGN}) SET(larg_names ${arg_names}) LIST(FIND larg_names "${arg}" is_arg_name) IF (is_arg_name GREATER -1) SET(${prefix}_${current_arg_name} ${current_arg_list}) SET(current_arg_name ${arg}) SET(current_arg_list) ELSE (is_arg_name GREATER -1) SET(loption_names ${option_names}) LIST(FIND loption_names "${arg}" is_option) IF (is_option GREATER -1) SET(${prefix}_${arg} TRUE) ELSE (is_option GREATER -1) SET(current_arg_list ${current_arg_list} ${arg}) ENDIF (is_option GREATER -1) ENDIF (is_arg_name GREATER -1) ENDFOREACH(arg) SET(${prefix}_${current_arg_name} ${current_arg_list}) ENDMACRO(PARSE_ARGUMENTS) online-accounts-api-0.1+16.04.20160212/cmake/FindLcov.cmake0000644000015600001650000000172012657306726023364 0ustar pbuserpbgroup00000000000000# - Find lcov # Will define: # # LCOV_EXECUTABLE - the lcov binary # GENHTML_EXECUTABLE - the genhtml executable # # Copyright (C) 2010 by Johannes Wienke # # This program 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 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # INCLUDE(FindPackageHandleStandardArgs) FIND_PROGRAM(LCOV_EXECUTABLE lcov) FIND_PROGRAM(GENHTML_EXECUTABLE genhtml) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lcov DEFAULT_MSG LCOV_EXECUTABLE GENHTML_EXECUTABLE) # only visible in advanced view MARK_AS_ADVANCED(LCOV_EXECUTABLE GENHTML_EXECUTABLE) online-accounts-api-0.1+16.04.20160212/tests/0000755000015600001650000000000012657307121020726 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/tests/daemon/0000755000015600001650000000000012657307121022171 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/0000755000015600001650000000000012657307121025555 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/fake_online_accounts_service.h0000644000015600001650000000340412657306726033632 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef OAD_FAKE_ONLINE_ACCOUNTS_SERVICE_H #define OAD_FAKE_ONLINE_ACCOUNTS_SERVICE_H #include #include #include class FakeOnlineAccountsService { public: FakeOnlineAccountsService(QtDBusMock::DBusMock *mock): m_mock(mock) { m_mock->registerTemplate("com.ubuntu.OnlineAccountsUi", ONLINE_ACCOUNTS_SERVICE_MOCK_TEMPLATE, QDBusConnection::SessionBus); } void setRequestAccessReply(const QVariantMap &reply) { mocked().call("SetRequestAccessReply", reply); } private: OrgFreedesktopDBusMockInterface &mocked() { return m_mock->mockInterface("com.ubuntu.OnlineAccountsUi", "/", "com.ubuntu.OnlineAccountsUi", QDBusConnection::SessionBus); } private: QtDBusMock::DBusMock *m_mock; }; #endif // OAD_FAKE_ONLINE_ACCOUNTS_SERVICE_H online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/dbus_apparmor.py0000644000015600001650000000221212657306726030774 0ustar pbuserpbgroup00000000000000'''D-Bus mock template for GetConnectionAppArmorSecurityContext ''' # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation; either version 3 of the License, or (at your option) any # later version. See http://www.gnu.org/copyleft/lgpl.html for the full text # of the license. __author__ = 'Alberto Mardegan' __email__ = 'alberto.mardegan@canonical.com' __copyright__ = '(c) 2015 Canonical Ltd.' __license__ = 'LGPL 3+' import dbus from dbusmock import MOCK_IFACE BUS_NAME = 'mocked.org.freedesktop.dbus' MAIN_OBJ = '/org/freedesktop/DBus' MAIN_IFACE = 'org.freedesktop.DBus' SYSTEM_BUS = False def load(mock, parameters): mock.AddMethod(MAIN_IFACE, 'GetConnectionAppArmorSecurityContext', 's', 's', 'ret = self.contexts.get(args[0], "unconfined")') mock.contexts = {} @dbus.service.method(MOCK_IFACE, in_signature='ss', out_signature='') def AddClient(self, client, context): '''Adds a client with its security context''' self.contexts[client] = context online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/online_accounts-service.py0000644000015600001650000000347212657306726032770 0ustar pbuserpbgroup00000000000000'''online-accounts-service mock template This creates the expected methods and properties of the com.ubuntu.OnlineAccountsUi service. By default, all actions are rejected. ''' # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation; either version 3 of the License, or (at your option) any # later version. See http://www.gnu.org/copyleft/lgpl.html for the full text # of the license. __author__ = 'Alberto Mardegan' __email__ = 'alberto.mardegan@canonical.com' __copyright__ = '(c) 2015 Canonical Ltd.' __license__ = 'LGPL 3+' import dbus from dbusmock import MOCK_IFACE BUS_NAME = 'com.ubuntu.OnlineAccountsUi' MAIN_OBJ = '/' MAIN_IFACE = 'com.ubuntu.OnlineAccountsUi' SYSTEM_BUS = False ERROR_PREFIX = 'com.ubuntu.OnlineAccountsUi.' ERROR_USER_CANCELED = ERROR_PREFIX + 'UserCanceled' ERROR_INVALID_PARAMETERS = ERROR_PREFIX + 'InvalidParameters' ERROR_INVALID_APPLICATION= ERROR_PREFIX + 'InvalidApplication' def load(mock, parameters): mock.AddMethod(MAIN_IFACE, 'requestAccess', 'a{sv}', 'a{sv}', 'ret = self.request_access(args[0])') mock.access_reply = {} mock.access_reply_error = {} def request_access(self, params): if 'errorName' in self.access_reply: raise dbus.exceptions.DBusException('Access error', name=self.access_reply['errorName']) return self.access_reply setattr(mock.__class__, "request_access", request_access) @dbus.service.method(MOCK_IFACE, in_signature='a{sv}', out_signature='') def SetRequestAccessReply(self, reply): '''Prepares the reply for the next RequestAccess call''' self.access_reply = reply online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/0000755000015600001650000000000012657307121026466 5ustar pbuserpbgroup00000000000000././@LongLink0000000000000000000000000000016700000000000011221 Lustar 00000000000000online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/com.ubuntu.OnlineAccounts.Manager.service.inonline-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/com.ubuntu.OnlineAccounts.0000644000015600001650000000013412657306726033521 0ustar pbuserpbgroup00000000000000[D-BUS Service] Name=com.ubuntu.OnlineAccounts.Manager Exec=${accountd_BINARY_DIR}/accountd online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/coolmail.service0000644000015600001650000000105312657306726031660 0ustar pbuserpbgroup00000000000000 e-mail Cool Mail general_myservice cool ././@LongLink0000000000000000000000000000015500000000000011216 Lustar 00000000000000online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/com.ubuntu.tests_coolshare.serviceonline-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/com.ubuntu.tests_coolshare0000644000015600001650000000027512657306726033726 0ustar pbuserpbgroup00000000000000 sharing Cool Share general_otherservice cool online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/applications/0000755000015600001650000000000012657307121031154 5ustar pbuserpbgroup00000000000000././@LongLink0000000000000000000000000000014600000000000011216 Lustar 00000000000000online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/applications/mailer.desktoponline-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/applications/mailer.deskto0000644000015600001650000000024312657306726033651 0ustar pbuserpbgroup00000000000000[Desktop Entry] Name=Easy Mailer Comment=Send and receive mail Exec=/bin/sh Icon=mailer-icon Terminal=false Type=Application Categories=Application;Network;Email; online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/mailer.application0000644000015600001650000000101412657306726032172 0ustar pbuserpbgroup00000000000000 Mailer application mailer-catalog mailer.desktop Mailer can retrieve your e-mails Mailer can even share stuff on CoolShare ././@LongLink0000000000000000000000000000016300000000000011215 Lustar 00000000000000online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/com.ubuntu.tests_application.applicationonline-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/com.ubuntu.tests_applicati0000644000015600001650000000066012657306726033713 0ustar pbuserpbgroup00000000000000 Mailer mailer-catalog mailer.desktop Mailer can even share stuff on CoolShare com.ubuntu.tests_application_0.3 online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/testsession.conf.in0000644000015600001650000000320612657306726032340 0ustar pbuserpbgroup00000000000000 session unix:tmpdir=/tmp ${CMAKE_CURRENT_BINARY_DIR}/data 60000 1000000000 1000000000 1000000000 120000 240000 100000 10000 100000 10000 50000 50000 50000 300000 online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/oauth1auth.service0000644000015600001650000000101612657306726032143 0ustar pbuserpbgroup00000000000000 e-mail OAuth 1 test general_myservice cool online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/data/cool.provider0000644000015600001650000000026012657306726031206 0ustar pbuserpbgroup00000000000000 Cool provider general_myprovider true online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/fake_dbus_apparmor.h0000644000015600001650000000330612657306726031566 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef OAD_FAKE_DBUS_APPARMOR_H #define OAD_FAKE_DBUS_APPARMOR_H #include #include class FakeDBusApparmor { public: FakeDBusApparmor(QtDBusMock::DBusMock *mock): m_mock(mock) { m_mock->registerTemplate("mocked.org.freedesktop.dbus", DBUS_APPARMOR_MOCK_TEMPLATE, QDBusConnection::SessionBus); } void addClient(const QString &client, const QString context) { mocked().call("AddClient", client, context); } private: OrgFreedesktopDBusMockInterface &mocked() { return m_mock->mockInterface("mocked.org.freedesktop.dbus", "/org/freedesktop/DBus", "org.freedesktop.DBus", QDBusConnection::SessionBus); } private: QtDBusMock::DBusMock *m_mock; }; #endif // OAD_FAKE_DBUS_APPARMOR_H online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/daemon_interface.h0000644000015600001650000000623412657306726031230 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef OAD_DAEMON_INTERFACE_H #define OAD_DAEMON_INTERFACE_H #include "OnlineAccountsDaemon/dbus_constants.h" #include #include #include #include #include #include #include #include class AccountInfo { public: AccountInfo(): accountId(0) {} AccountInfo(uint accountId, const QVariantMap &details): accountId(accountId), details(details) {} uint id() const { return accountId; } QVariantMap data() const { return details; } private: friend QDBusArgument &operator<<(QDBusArgument &, const AccountInfo &); friend const QDBusArgument &operator>>(const QDBusArgument &, AccountInfo &); uint accountId; QVariantMap details; }; Q_DECLARE_METATYPE(AccountInfo) QDBusArgument &operator<<(QDBusArgument &argument, const AccountInfo &info); const QDBusArgument &operator>>(const QDBusArgument &argument, AccountInfo &info); /* Avoid using QDBusInterface which does a blocking introspection call. */ class DaemonInterface: public QDBusAbstractInterface { Q_OBJECT public: DaemonInterface(QObject *parent = 0); ~DaemonInterface() {} QDBusPendingCall getAccounts(const QVariantMap &filters) { return asyncCall(QStringLiteral("GetAccounts"), filters); } QDBusPendingCall authenticate(uint accountId, const QString &service, bool interactive, bool invalidate, const QVariantMap ¶meters) { return asyncCall(QStringLiteral("Authenticate"), accountId, service, interactive, invalidate, parameters); } QDBusPendingCall requestAccess(const QString &service, const QVariantMap ¶meters) { return asyncCall(QStringLiteral("RequestAccess"), service, parameters); } Q_SIGNALS: void accountChanged(const QString &service, const AccountInfo &info); private: bool connect(const char *signal, const char *signature, QObject *receiver, const char *slot) { return connection().connect(service(), path(), interface(), QLatin1String(signal), QLatin1String(signature), receiver, slot); } }; #endif // OAD_DAEMON_INTERFACE_H online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/daemon_interface.cpp0000644000015600001650000000367612657306726031572 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "daemon_interface.h" #include #include QDBusArgument &operator<<(QDBusArgument &argument, const AccountInfo &info) { argument.beginStructure(); argument << info.accountId << info.details; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, AccountInfo &info) { argument.beginStructure(); argument >> info.accountId >> info.details; argument.endStructure(); return argument; } DaemonInterface::DaemonInterface(QObject *parent): QDBusAbstractInterface(ONLINE_ACCOUNTS_MANAGER_SERVICE_NAME, ONLINE_ACCOUNTS_MANAGER_PATH, ONLINE_ACCOUNTS_MANAGER_INTERFACE, QDBusConnection::sessionBus(), parent) { setTimeout(INT_MAX); qDBusRegisterMetaType(); qDBusRegisterMetaType>(); bool ok = connect("AccountChanged", "s(ua{sv})", this, SIGNAL(accountChanged(const QString&,const AccountInfo&))); if (Q_UNLIKELY(!ok)) { qCritical() << "Connection to AccountChanged signal failed"; } } online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/fake_signond.h0000644000015600001650000000337512657306726030377 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef OAD_FAKE_SIGNOND_H #define OAD_FAKE_SIGNOND_H #include #include class FakeSignond { public: FakeSignond(QtDBusMock::DBusMock *mock): m_mock(mock) { m_mock->registerTemplate("com.google.code.AccountsSSO.SingleSignOn", SIGNOND_MOCK_TEMPLATE, QDBusConnection::SessionBus); } void addIdentity(uint id, const QVariantMap &info) { mockedAuthService().call("AddIdentity", id, info); } private: OrgFreedesktopDBusMockInterface &mockedAuthService() { return m_mock->mockInterface("com.google.code.AccountsSSO.SingleSignOn", "/com/google/code/AccountsSSO/SingleSignOn", "com.google.code.AccountsSSO.SingleSignOn.AuthService", QDBusConnection::SessionBus); } private: QtDBusMock::DBusMock *m_mock; }; #endif // OAD_FAKE_SIGNOND_H online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/CMakeLists.txt0000644000015600001650000000274012657306726030332 0ustar pbuserpbgroup00000000000000set(TEST tst_daemon) set(SOURCES daemon_interface.cpp functional_tests.cpp ) pkg_check_modules(QTDBUSMOCK REQUIRED libqtdbusmock-1) pkg_check_modules(QTDBUSTEST REQUIRED libqtdbustest-1) pkg_check_modules(ACCOUNTSQT accounts-qt5 REQUIRED) add_executable(${TEST} ${SOURCES}) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${OnlineAccountsQt_SOURCE_DIR}/.. ${OnlineAccountsDaemon_SOURCE_DIR}/.. ${ACCOUNTSQT_INCLUDE_DIRS} ${QTDBUSMOCK_INCLUDE_DIRS} ${QTDBUSTEST_INCLUDE_DIRS} ) add_definitions( -DTEST_DBUS_CONFIG_FILE="${CMAKE_CURRENT_BINARY_DIR}/data/testsession.conf" -DTEST_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" -DTEST_PROCESS="${CMAKE_CURRENT_SOURCE_DIR}/test_process.py" -DSIGNOND_MOCK_TEMPLATE="${CMAKE_CURRENT_SOURCE_DIR}/signond.py" -DDBUS_APPARMOR_MOCK_TEMPLATE="${CMAKE_CURRENT_SOURCE_DIR}/dbus_apparmor.py" -DONLINE_ACCOUNTS_SERVICE_MOCK_TEMPLATE="${CMAKE_CURRENT_SOURCE_DIR}/online_accounts-service.py" ) configure_file(data/testsession.conf.in data/testsession.conf) configure_file(data/com.ubuntu.OnlineAccounts.Manager.service.in data/com.ubuntu.OnlineAccounts.Manager.service ) target_link_libraries(${TEST} OnlineAccountsQt ${ACCOUNTSQT_LIBRARIES} ${QTDBUSMOCK_LIBRARIES} ${QTDBUSTEST_LIBRARIES} ) qt5_use_modules(${TEST} Core DBus Test) set_target_properties(${TEST} PROPERTIES AUTOMOC TRUE) add_test(${TEST} ${XVFB_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) add_dependencies(check ${TEST}) online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/test_process.py0000755000015600001650000000423612657306726030666 0ustar pbuserpbgroup00000000000000#! /usr/bin/python3 # coding: UTF-8 import argparse import dbus import dbus.mainloop.glib from gi.repository import GLib import json import sys import traceback BUS_NAME = 'com.ubuntu.OnlineAccounts.Manager' MAIN_OBJ = '/com/ubuntu/OnlineAccounts/Manager' MAIN_IFACE = 'com.ubuntu.OnlineAccounts.Manager' class TestProcess: def __init__(self, bus): self.parser = self.create_parser() self.main_loop = GLib.MainLoop() self.manager = bus.get_object(BUS_NAME, MAIN_OBJ) self.manager.connect_to_signal("AccountChanged", self.on_account_changed, dbus_interface=MAIN_IFACE) def get_accounts(self, args): filters = dbus.Dictionary(signature='sv') if args.filters: filters.update(json.loads(args.filters)) print('%s' % json.dumps(self.manager.GetAccounts(filters), sort_keys=True), flush=True) def on_account_changed(self, serviceId, accountInfo): info = json.dumps(accountInfo, sort_keys=True) print('AccountChanged %s %s' % (serviceId, info), flush=True) def on_line_read(self, line): if not line: self.main_loop.quit() return args = self.parser.parse_args(line.split()) args.func(args) def run(self): GLib.io_add_watch(0, GLib.IO_IN | GLib.IO_HUP, self.on_input) self.main_loop.run() def on_input(self, source, reason): if reason & GLib.IO_IN: line = sys.stdin.readline() self.on_line_read(line.strip()) else: self.on_line_read('') return True def create_parser(self): parser = argparse.ArgumentParser(description='Test process') subparsers = parser.add_subparsers() parser_accounts = subparsers.add_parser('GetAccounts') parser_accounts.add_argument('-f', '--filters') parser_accounts.set_defaults(func=self.get_accounts) return parser dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) bus = dbus.SessionBus() print('%s' % bus.get_unique_name(), flush=True) try: app = TestProcess(bus) except dbus.DBusException: traceback.print_exc() sys.exit(1) app.run() online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/functional_tests.cpp0000644000015600001650000004713312657306726031667 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "OnlineAccountsDaemon/dbus_constants.h" #include "daemon_interface.h" #include "fake_dbus_apparmor.h" #include "fake_online_accounts_service.h" #include "fake_signond.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace QTest { template<> char *toString(const QSet &set) { QByteArray ba = "QSet("; QStringList list; Q_FOREACH(int i, set) { list.append(QString::number(i)); } ba += list.join(", "); ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const QVariantMap &map) { QJsonDocument doc(QJsonObject::fromVariantMap(map)); return qstrdup(doc.toJson(QJsonDocument::Compact).data()); } } // QTest namespace class TestProcess: public QProcess { Q_OBJECT public: TestProcess(QObject *parent = 0): QProcess(parent), m_replyExpected(false) { setProgram(QStringLiteral(TEST_PROCESS)); setReadChannel(QProcess::StandardOutput); setProcessChannelMode(QProcess::ForwardedErrorChannel); start(); QVERIFY(waitForStarted()); QVERIFY(waitForReadyRead()); m_uniqueName = QString::fromUtf8(readLine()).trimmed(); QObject::connect(this, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadyRead())); } ~TestProcess() { quit(); } QString uniqueName() const { return m_uniqueName; } void quit() { write("\n"); waitForFinished(); } QList getAccounts(const QVariantMap &filters) { QJsonDocument doc(QJsonObject::fromVariantMap(filters)); m_replyExpected = true; write("GetAccounts -f "); write(doc.toJson(QJsonDocument::Compact) + '\n'); waitForReadyRead(); doc = QJsonDocument::fromJson(readLine()); m_replyExpected = false; QList accountInfos; Q_FOREACH(const QJsonValue &v, doc.array()) { QJsonArray a = v.toArray(); accountInfos.append(AccountInfo(a.at(0).toInt(), a.at(1).toObject().toVariantMap())); } return accountInfos; } private Q_SLOTS: void onReadyRead() { if (m_replyExpected) return; QByteArray line = readLine().trimmed(); QList parts = line.split(' '); if (parts[0] != "AccountChanged") return; QByteArray changes = parts.mid(2).join(' '); QJsonDocument doc = QJsonDocument::fromJson(changes); QJsonArray a = doc.array(); Q_EMIT accountChanged(QString::fromUtf8(parts[1]), AccountInfo(a.at(0).toInt(), a.at(1).toObject().toVariantMap())); } Q_SIGNALS: void accountChanged(QString serviceId, AccountInfo account); private: QString m_uniqueName; bool m_replyExpected; }; class FunctionalTests: public QObject { Q_OBJECT struct EnvSetup { EnvSetup(); }; public: FunctionalTests(); private Q_SLOTS: void testGetAccountsFiltering_data(); void testGetAccountsFiltering(); void testAuthenticate_data(); void testAuthenticate(); void testRequestAccess_data(); void testRequestAccess(); void testAccountChanges(); void testLifetime(); void cleanupTestCase(); private: void clearDb(); private: EnvSetup m_env; QtDBusTest::DBusTestRunner m_dbus; QtDBusMock::DBusMock m_mock; FakeDBusApparmor m_dbusApparmor; FakeOnlineAccountsService m_onlineAccounts; FakeSignond m_signond; int m_firstAccountId; int m_account3CredentialsId; }; FunctionalTests::EnvSetup::EnvSetup() { qputenv("ACCOUNTS", "/tmp/"); qputenv("AG_APPLICATIONS", TEST_DATA_DIR); qputenv("AG_SERVICES", TEST_DATA_DIR); qputenv("AG_SERVICE_TYPES", TEST_DATA_DIR); qputenv("AG_PROVIDERS", TEST_DATA_DIR); qputenv("XDG_DATA_HOME", TEST_DATA_DIR); qputenv("SSO_USE_PEER_BUS", "0"); qputenv("OAD_TIMEOUT", "2"); qputenv("OAD_TESTING", "1"); } FunctionalTests::FunctionalTests(): QObject(), m_dbus(TEST_DBUS_CONFIG_FILE), m_mock(m_dbus), m_dbusApparmor(&m_mock), m_onlineAccounts(&m_mock), m_signond(&m_mock), m_account3CredentialsId(35) { clearDb(); /* Populate the accounts DB */ Accounts::Manager *manager = new Accounts::Manager(this); Accounts::Service coolMail = manager->service("coolmail"); Accounts::Service coolShare = manager->service("com.ubuntu.tests_coolshare"); Accounts::Service oauth1auth = manager->service("oauth1auth"); Accounts::Account *account1 = manager->createAccount("cool"); QVERIFY(account1 != 0); account1->setEnabled(true); account1->setDisplayName("CoolAccount 1"); // Do not create this identity, we want it to be non-existing account1->setCredentialsId(249); account1->selectService(coolMail); account1->setEnabled(true); account1->syncAndBlock(); m_firstAccountId = account1->id() - 1; Accounts::Account *account2 = manager->createAccount("cool"); QVERIFY(account2 != 0); account2->setEnabled(true); account2->setDisplayName("CoolAccount 2"); account2->selectService(coolMail); account2->setEnabled(false); account2->selectService(coolShare); account2->setEnabled(true); account2->syncAndBlock(); Accounts::Account *account3 = manager->createAccount("cool"); QVERIFY(account3 != 0); account3->setEnabled(true); account3->setDisplayName("CoolAccount 3"); account3->setValue("color", "red"); account3->setValue("size", "big"); account3->setCredentialsId(m_account3CredentialsId); account3->selectService(coolMail); account3->setEnabled(true); account3->selectService(oauth1auth); account3->setEnabled(true); account3->syncAndBlock(); delete manager; m_dbus.startServices(); } void FunctionalTests::clearDb() { QDir dbroot(QString::fromLatin1(qgetenv("ACCOUNTS"))); dbroot.remove("accounts.db"); } void FunctionalTests::testGetAccountsFiltering_data() { QTest::addColumn("filters"); QTest::addColumn("securityContext"); QTest::addColumn >("expectedAccountIds"); QVariantMap filters; QTest::newRow("empty filters") << filters << "unconfined" << (QList() << 1 << 2 << 3); QTest::newRow("empty filters, confined") << filters << "com.ubuntu.tests_application_0.2" << (QList() << 2); filters[ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID] = "coolmail"; QTest::newRow("by service ID") << filters << "unconfined" << (QList() << 1 << 3); } void FunctionalTests::testGetAccountsFiltering() { QFETCH(QVariantMap, filters); QFETCH(QString, securityContext); QFETCH(QList, expectedAccountIds); DaemonInterface *daemon = new DaemonInterface; TestProcess testProcess; m_dbusApparmor.addClient(testProcess.uniqueName(), securityContext); QList accountInfos = testProcess.getAccounts(filters); QList accountIds; Q_FOREACH(const AccountInfo &info, accountInfos) { accountIds.append(info.id() + m_firstAccountId); } QCOMPARE(accountIds.toSet(), expectedAccountIds.toSet()); delete daemon; } void FunctionalTests::testAuthenticate_data() { QTest::addColumn("accountId"); QTest::addColumn("serviceId"); QTest::addColumn("interactive"); QTest::addColumn("invalidate"); QTest::addColumn("authParams"); QTest::addColumn("expectedCredentials"); QTest::addColumn("errorName"); QVariantMap authParams; QVariantMap credentials; QTest::newRow("invalid account ID") << 12412341 << "coolmail" << false << false << authParams << credentials << ONLINE_ACCOUNTS_ERROR_PERMISSION_DENIED; authParams["errorName"] = "com.google.code.AccountsSSO.SingleSignOn.Error.Network"; QTest::newRow("Authentication error") << 3 << "coolmail" << false << false << authParams << credentials << "com.ubuntu.OnlineAccounts.Error.Network"; authParams.clear(); authParams["one"] = 1; credentials["one"] = 1; credentials["host"] = "coolmail.ex"; credentials["UiPolicy"] = 2; QTest::newRow("no interactive, no invalidate") << 3 << "coolmail" << false << false << authParams << credentials << QString(); credentials["UiPolicy"] = 0; QTest::newRow("interactive, no invalidate") << 3 << "coolmail" << true << false << authParams << credentials << QString(); credentials["ForceTokenRefresh"] = true; QTest::newRow("interactive, invalidate") << 3 << "coolmail" << true << true << authParams << credentials << QString(); authParams.clear(); credentials.clear(); credentials["UiPolicy"] = 0; credentials["ConsumerKey"] = "c0nsum3rk3y"; credentials["ConsumerSecret"] = "c0nsum3rs3cr3t"; QTest::newRow("OAuth1 client data") << 3 << "oauth1auth" << true << false << authParams << credentials << QString(); authParams.clear(); authParams["ConsumerKey"] = "overridden"; credentials.clear(); credentials["UiPolicy"] = 0; credentials["ConsumerKey"] = "overridden"; credentials["ConsumerSecret"] = "c0nsum3rs3cr3t"; QTest::newRow("OAuth1 client data, overridden") << 3 << "oauth1auth" << true << false << authParams << credentials << QString(); } void FunctionalTests::testAuthenticate() { QFETCH(int, accountId); QFETCH(QString, serviceId); QFETCH(bool, interactive); QFETCH(bool, invalidate); QFETCH(QVariantMap, authParams); QFETCH(QVariantMap, expectedCredentials); QFETCH(QString, errorName); m_signond.addIdentity(m_account3CredentialsId, QVariantMap()); DaemonInterface *daemon = new DaemonInterface; QDBusPendingReply reply = daemon->authenticate(m_firstAccountId + accountId, serviceId, interactive, invalidate, authParams); reply.waitForFinished(); if (errorName.isEmpty()) { QVERIFY(!reply.isError()); QVariantMap credentials = reply.argumentAt<0>(); // Add the requestor PID expectedCredentials["requestorPid"] = getpid(); QCOMPARE(credentials, expectedCredentials); } else { QVERIFY(reply.isError()); QCOMPARE(reply.error().name(), errorName); } delete daemon; } void FunctionalTests::testRequestAccess_data() { QTest::addColumn("serviceId"); QTest::addColumn("authParams"); QTest::addColumn("accessReply"); QTest::addColumn("expectedAccountId"); QTest::addColumn("expectedAccountInfo"); QTest::addColumn("expectedCredentials"); QTest::addColumn("errorName"); QVariantMap authParams; QVariantMap accessReply; QVariantMap accountInfo; QVariantMap credentials; QTest::newRow("access denied") << "coolmail" << authParams << accessReply << 0 << accountInfo << credentials << ONLINE_ACCOUNTS_ERROR_PERMISSION_DENIED; accessReply["accountId"] = m_firstAccountId + 3; accountInfo[ONLINE_ACCOUNTS_INFO_KEY_AUTH_METHOD] = ONLINE_ACCOUNTS_AUTH_METHOD_OAUTH2; accountInfo[ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME] = "CoolAccount 3"; accountInfo[ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID] = "coolmail"; accountInfo["settings/auth/mechanism"] = "user_agent"; accountInfo["settings/auth/method"] = "oauth2"; accountInfo["settings/auth/oauth2/user_agent/host"] = "coolmail.ex"; accountInfo["settings/auto-explode-after"] = 10; accountInfo["settings/color"] = "green"; accountInfo["settings/size"] = "big"; credentials["host"] = "coolmail.ex"; QTest::newRow("no auth params") << "coolmail" << authParams << accessReply << m_firstAccountId + 3 << accountInfo << credentials << ""; authParams["one"] = 1; credentials["one"] = 1; QTest::newRow("with auth params") << "coolmail" << authParams << accessReply << m_firstAccountId + 3 << accountInfo << credentials << ""; } void FunctionalTests::testRequestAccess() { QFETCH(QString, serviceId); QFETCH(QVariantMap, authParams); QFETCH(QVariantMap, accessReply); QFETCH(int, expectedAccountId); QFETCH(QVariantMap, expectedAccountInfo); QFETCH(QVariantMap, expectedCredentials); QFETCH(QString, errorName); m_onlineAccounts.setRequestAccessReply(accessReply); m_signond.addIdentity(m_account3CredentialsId, QVariantMap()); DaemonInterface *daemon = new DaemonInterface; QDBusPendingReply reply = daemon->requestAccess(serviceId, authParams); reply.waitForFinished(); if (errorName.isEmpty()) { QVERIFY(!reply.isError()); AccountInfo accountInfo = reply.argumentAt<0>(); QVariantMap credentials = reply.argumentAt<1>(); QCOMPARE(int(accountInfo.id()), expectedAccountId); QCOMPARE(accountInfo.data(), expectedAccountInfo); QCOMPARE(credentials, expectedCredentials); } else { QVERIFY(reply.isError()); QCOMPARE(reply.error().name(), errorName); } delete daemon; } void FunctionalTests::testAccountChanges() { DaemonInterface *daemon = new DaemonInterface; /* First, we make a call to the service so that it knows about our client * and will later notify it about changes. */ QVariantMap filters; filters["applicationId"] = "com.ubuntu.tests_application"; TestProcess testProcess; QSignalSpy accountChanged(&testProcess, SIGNAL(accountChanged(QString,AccountInfo))); QList accountInfos = testProcess.getAccounts(filters); QList initialAccountIds; Q_FOREACH(const AccountInfo &info, accountInfos) { initialAccountIds.append(info.id()); } /* Create a new account */ Accounts::Manager *manager = new Accounts::Manager(this); Accounts::Service coolShare = manager->service("com.ubuntu.tests_coolshare"); Accounts::Account *account = manager->createAccount("cool"); QVERIFY(account != 0); account->setEnabled(true); account->setDisplayName("New account"); account->selectService(coolShare); account->setEnabled(true); account->syncAndBlock(); QTRY_COMPARE(accountChanged.count(), 1); QString serviceId = accountChanged.at(0).at(0).toString(); AccountInfo accountInfo = accountChanged.at(0).at(1).value(); QCOMPARE(serviceId, coolShare.name()); QCOMPARE(accountInfo.id(), account->id()); QVariantMap expectedAccountInfo; expectedAccountInfo["authMethod"] = ONLINE_ACCOUNTS_AUTH_METHOD_UNKNOWN; expectedAccountInfo["changeType"] = ONLINE_ACCOUNTS_INFO_CHANGE_ENABLED; expectedAccountInfo["displayName"] = "New account"; expectedAccountInfo["serviceId"] = "com.ubuntu.tests_coolshare"; QCOMPARE(accountInfo.data(), expectedAccountInfo); /* Change a setting */ accountChanged.clear(); account->setValue("color", "blue"); account->syncAndBlock(); QTRY_COMPARE(accountChanged.count(), 1); serviceId = accountChanged.at(0).at(0).toString(); accountInfo = accountChanged.at(0).at(1).value(); QCOMPARE(serviceId, coolShare.name()); QCOMPARE(accountInfo.id(), account->id()); expectedAccountInfo["authMethod"] = ONLINE_ACCOUNTS_AUTH_METHOD_UNKNOWN; expectedAccountInfo["changeType"] = ONLINE_ACCOUNTS_INFO_CHANGE_UPDATED; expectedAccountInfo["settings/color"] = "blue"; expectedAccountInfo["displayName"] = "New account"; expectedAccountInfo["serviceId"] = "com.ubuntu.tests_coolshare"; QCOMPARE(accountInfo.data(), expectedAccountInfo); /* Delete the account */ accountChanged.clear(); account->remove(); account->syncAndBlock(); QTRY_COMPARE(accountChanged.count(), 1); serviceId = accountChanged.at(0).at(0).toString(); accountInfo = accountChanged.at(0).at(1).value(); QCOMPARE(serviceId, coolShare.name()); QCOMPARE(accountInfo.id(), account->id()); expectedAccountInfo["authMethod"] = ONLINE_ACCOUNTS_AUTH_METHOD_UNKNOWN; expectedAccountInfo["changeType"] = ONLINE_ACCOUNTS_INFO_CHANGE_DISABLED; expectedAccountInfo["displayName"] = "New account"; expectedAccountInfo["serviceId"] = "com.ubuntu.tests_coolshare"; QCOMPARE(accountInfo.data(), expectedAccountInfo); delete daemon; } void FunctionalTests::testLifetime() { /* Make a dbus call, and have signond reply after 3 seconds; make sure that * the online accounts daemon doesn't time out. */ m_signond.addIdentity(m_account3CredentialsId, QVariantMap()); DaemonInterface *daemon = new DaemonInterface; QDBusServiceWatcher watcher(ONLINE_ACCOUNTS_MANAGER_SERVICE_NAME, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration); QSignalSpy unregistered(&watcher, SIGNAL(serviceUnregistered(const QString &))); QVariantMap authParams; authParams["delay"] = 3; QDBusPendingReply reply = daemon->authenticate(m_firstAccountId + 3, "coolmail", false, false, authParams); reply.waitForFinished(); QVERIFY(!reply.isError()); QVariantMap expectedCredentials(authParams); expectedCredentials["UiPolicy"] = 2; expectedCredentials["host"] = "coolmail.ex"; expectedCredentials["requestorPid"] = getpid(); QVariantMap credentials = reply.argumentAt<0>(); QCOMPARE(credentials, expectedCredentials); QCOMPARE(unregistered.count(), 0); delete daemon; } void FunctionalTests::cleanupTestCase() { QDBusConnection conn = QDBusConnection::sessionBus(); QString serviceName(QStringLiteral(ONLINE_ACCOUNTS_MANAGER_SERVICE_NAME)); QDBusReply reply = conn.interface()->isServiceRegistered(serviceName); if (reply.value()) { /* Let'äs wait for the daemon to quit */ QDBusServiceWatcher watcher(serviceName, conn, QDBusServiceWatcher::WatchForUnregistration); QSignalSpy unregistered(&watcher, SIGNAL(serviceUnregistered(const QString &))); QTRY_COMPARE(unregistered.count(), 1); } } QTEST_MAIN(FunctionalTests) #include "functional_tests.moc" online-accounts-api-0.1+16.04.20160212/tests/daemon/functional_tests/signond.py0000644000015600001650000000671012657306726027606 0ustar pbuserpbgroup00000000000000'''signond mock template This creates the expected methods and properties of the com.google.code.AccountsSSO.SingleSignOn service. ''' # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation; either version 3 of the License, or (at your option) any # later version. See http://www.gnu.org/copyleft/lgpl.html for the full text # of the license. __author__ = 'Alberto Mardegan' __email__ = 'alberto.mardegan@canonical.com' __copyright__ = '(c) 2015 Canonical Ltd.' __license__ = 'LGPL 3+' import dbus import time from dbusmock import MOCK_IFACE import dbusmock BUS_NAME = 'com.google.code.AccountsSSO.SingleSignOn' MAIN_OBJ = '/com/google/code/AccountsSSO/SingleSignOn' AUTH_SERVICE_IFACE = 'com.google.code.AccountsSSO.SingleSignOn.AuthService' MAIN_IFACE = AUTH_SERVICE_IFACE IDENTITY_IFACE = 'com.google.code.AccountsSSO.SingleSignOn.Identity' AUTH_SESSION_IFACE = 'com.google.code.AccountsSSO.SingleSignOn.AuthSession' SYSTEM_BUS = False ERROR_PREFIX = 'com.google.code.AccountsSSO.SingleSignOn.Error.' ERROR_IDENTITY_NOT_FOUND = ERROR_PREFIX + 'IdentityNotFound' ERROR_PERMISSION_DENIED = ERROR_PREFIX + 'PermissionDenied' ERROR_USER_INTERACTION= ERROR_PREFIX + 'UserInteraction' def get_identity(self, identity): if identity not in self.identities: raise dbus.exceptions.DBusException('Identity not found', name=ERROR_IDENTITY_NOT_FOUND) path = '/Identity%s' % identity if not path in dbusmock.get_objects(): self.AddObject(path, IDENTITY_IFACE, {}, [ ('getInfo', '', 'a{sv}', 'ret = self.parent.identities[%s]' % identity) ]) identity_obj = dbusmock.get_object(path) identity_obj.parent = self return (path, self.identities[identity]) def auth_session_process(identity, params, method): if 'errorName' in params: raise dbus.exceptions.DBusException('Authentication error', name=params['errorName']) if 'delay' in params: time.sleep(params['delay']) return params def get_auth_session_object_path(self, identity, method): if identity != 0 and (identity not in self.identities): raise dbus.exceptions.DBusException('Identity not found', name=ERROR_IDENTITY_NOT_FOUND) path = '/AuthSession%s' % self.sessions_counter self.sessions_counter += 1 self.AddObject(path, AUTH_SESSION_IFACE, {}, [ ('process', 'a{sv}s', 'a{sv}', 'ret = self.auth_session_process(self.identity, args[0], args[1])'), ]) auth_session = dbusmock.get_object(path) auth_session.auth_session_process = auth_session_process auth_session.identity = identity auth_session.method = method return path def load(mock, parameters): mock.get_identity = get_identity mock.get_auth_session_object_path = get_auth_session_object_path mock.AddMethods(AUTH_SERVICE_IFACE, [ ('getIdentity', 'u', 'oa{sv}', 'ret = self.get_identity(self, args[0])'), ('getAuthSessionObjectPath', 'us', 's', 'ret = self.get_auth_session_object_path(self, args[0], args[1])'), ]) mock.sessions_counter = 1 mock.identities = {} mock.auth_sessions = {} mock.auth_replies = {} @dbus.service.method(MOCK_IFACE, in_signature='ua{sv}', out_signature='') def AddIdentity(self, identity, data): self.identities[identity] = data online-accounts-api-0.1+16.04.20160212/tests/daemon/CMakeLists.txt0000644000015600001650000000004312657306726024740 0ustar pbuserpbgroup00000000000000add_subdirectory(functional_tests) online-accounts-api-0.1+16.04.20160212/tests/lib/0000755000015600001650000000000012657307121021474 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/tests/lib/OnlineAccounts/0000755000015600001650000000000012657307121024420 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/tests/lib/OnlineAccounts/functional_tests/0000755000015600001650000000000012657307121030004 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/tests/lib/OnlineAccounts/functional_tests/CMakeLists.txt0000644000015600001650000000120212657306726032551 0ustar pbuserpbgroup00000000000000set(TEST functional_tests) set(SOURCES functional_tests.cpp ) pkg_check_modules(QTDBUSMOCK REQUIRED libqtdbusmock-1) pkg_check_modules(QTDBUSTEST REQUIRED libqtdbustest-1) add_executable(${TEST} ${SOURCES}) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${OnlineAccountsQt_SOURCE_DIR}/.. ${OnlineAccountsDaemon_SOURCE_DIR}/.. ${QTDBUSMOCK_INCLUDE_DIRS} ${QTDBUSTEST_INCLUDE_DIRS} ) target_link_libraries(${TEST} OnlineAccountsQt ${QTDBUSMOCK_LIBRARIES} ${QTDBUSTEST_LIBRARIES} ) qt5_use_modules(${TEST} Core Test) add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) add_dependencies(check ${TEST}) ././@LongLink0000000000000000000000000000014600000000000011216 Lustar 00000000000000online-accounts-api-0.1+16.04.20160212/tests/lib/OnlineAccounts/functional_tests/functional_tests.cpponline-accounts-api-0.1+16.04.20160212/tests/lib/OnlineAccounts/functional_tests/functional_tests.cp0000644000015600001650000005267512657306732033742 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015-2016 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "OnlineAccounts/Account" #include "OnlineAccounts/Manager" #include "OnlineAccounts/OAuth1Data" #include "OnlineAccounts/OAuth2Data" #include "OnlineAccounts/PasswordData" #include "OnlineAccounts/account_info.h" #include "OnlineAccountsDaemon/dbus_constants.h" #include #include #include #include #include namespace QTest { template<> char *toString(const QVariantMap &map) { QJsonDocument doc(QJsonObject::fromVariantMap(map)); return qstrdup(doc.toJson(QJsonDocument::Compact).data()); } } // QTest namespace class FunctionalTests: public QObject { Q_OBJECT public: FunctionalTests(); OrgFreedesktopDBusMockInterface &mocked() { return m_mock.mockInterface(ONLINE_ACCOUNTS_MANAGER_SERVICE_NAME, ONLINE_ACCOUNTS_MANAGER_PATH, ONLINE_ACCOUNTS_MANAGER_INTERFACE, QDBusConnection::SessionBus); } void addMockedMethod(const QString &name, const QString &in_sig, const QString &out_sig, const QString &code) { return mocked().AddMethod(ONLINE_ACCOUNTS_MANAGER_INTERFACE, name, in_sig, out_sig, code).waitForFinished(); } void emitAccountChanged(const QString &service, uint accountId, const QVariantMap &changes) { QVariantList args; args << service; OnlineAccounts::AccountInfo accountInfo(accountId, changes); args << QVariant::fromValue(accountInfo); mocked().EmitSignal(ONLINE_ACCOUNTS_MANAGER_INTERFACE, "AccountChanged", "s(ua{sv})", args); } private Q_SLOTS: void testManagerReady_data(); void testManagerReady(); void testManagerAvailableAccounts_data(); void testManagerAvailableAccounts(); void testManagerAccount(); void testManagerRequestAccess_data(); void testManagerRequestAccess(); void testAccountData_data(); void testAccountData(); void testAccountChanges(); void testPendingCallWatcher(); void testAuthentication(); void testAuthenticationErrors_data(); void testAuthenticationErrors(); private: QtDBusTest::DBusTestRunner m_dbus; QtDBusMock::DBusMock m_mock; }; FunctionalTests::FunctionalTests(): QObject(), m_mock(m_dbus) { m_mock.registerCustomMock(ONLINE_ACCOUNTS_MANAGER_SERVICE_NAME, ONLINE_ACCOUNTS_MANAGER_PATH, ONLINE_ACCOUNTS_MANAGER_INTERFACE, QDBusConnection::SessionBus); m_dbus.startServices(); } void FunctionalTests::testManagerReady_data() { QTest::addColumn("haveGetAccountsMethod"); QTest::newRow("no GetAccounts method") << false; QTest::newRow("with GetAccounts method") << true; } void FunctionalTests::testManagerReady() { QFETCH(bool, haveGetAccountsMethod); if (haveGetAccountsMethod) { addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []"); } OnlineAccounts::Manager manager("my-app"); QSignalSpy ready(&manager, SIGNAL(ready())); manager.waitForReady(); QVERIFY(manager.isReady()); QCOMPARE(ready.count(), 1); } void FunctionalTests::testManagerAvailableAccounts_data() { QTest::addColumn("reply"); QTest::addColumn >("expectedIds"); QTest::addColumn("expectedDisplayNames"); QTest::newRow("no accounts") << "ret = []" << QList() << QStringList(); QTest::newRow("one account, no data") << "ret = [(1, {'displayName': 'Tom'})]" << (QList() << 1) << (QStringList() << "Tom"); } void FunctionalTests::testManagerAvailableAccounts() { QFETCH(QString, reply); QFETCH(QList, expectedIds); QFETCH(QStringList, expectedDisplayNames); addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", reply); OnlineAccounts::Manager manager("my-app"); manager.waitForReady(); QList ids; QStringList displayNames; Q_FOREACH(OnlineAccounts::Account *account, manager.availableAccounts()) { ids.append(account->id()); displayNames.append(account->displayName()); } QCOMPARE(ids, expectedIds); QCOMPARE(displayNames, expectedDisplayNames); } void FunctionalTests::testManagerAccount() { addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = [(1, {'displayName': 'John'})]"); OnlineAccounts::Manager manager("my-app"); manager.waitForReady(); // retrieve an invalid account OnlineAccounts::Account *account = manager.account(4); QVERIFY(!account); // valid account account = manager.account(1); QVERIFY(account); QCOMPARE(account->displayName(), QString("John")); } void FunctionalTests::testManagerRequestAccess_data() { QTest::addColumn("reply"); QTest::addColumn("waitForFinished"); QTest::addColumn("errorCode"); QTest::addColumn("displayName"); QTest::addColumn("accessToken"); QTest::newRow("dbus error") << "raise dbus.exceptions.DBusException('org.foo.bar', 'not foobarized')" << true << int(OnlineAccounts::Error::PermissionDenied) << "" << ""; QTest::newRow("access granted") << "ret = ((1, {'displayName': 'Bob'}),{'AccessToken':'GoOn'})" << true << int(0) << "Bob" << "GoOn"; QTest::newRow("access granted, no wait") << "ret = ((1, {'displayName': 'Bob'}),{'AccessToken':'GoOn'})" << false << int(0) << "Bob" << "GoOn"; } void FunctionalTests::testManagerRequestAccess() { QFETCH(QString, reply); QFETCH(bool, waitForFinished); QFETCH(int, errorCode); QFETCH(QString, displayName); QFETCH(QString, accessToken); addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []"); addMockedMethod("RequestAccess", "sa{sv}", "(ua{sv})a{sv}", reply); OnlineAccounts::Manager manager("my-app"); manager.waitForReady(); OnlineAccounts::OAuth2Data oauth; oauth.setClientId("happy app"); OnlineAccounts::PendingCall call = manager.requestAccess("my-service", oauth); if (waitForFinished) { call.waitForFinished(); QVERIFY(call.isFinished()); } OnlineAccounts::RequestAccessReply accessReply(call); QCOMPARE(int(accessReply.error().code()), errorCode); OnlineAccounts::Account *account = accessReply.account(); if (errorCode > 0) { QVERIFY(!account); } else { QVERIFY(account); QCOMPARE(account->displayName(), displayName); } OnlineAccounts::OAuth2Reply oauthReply(call); QCOMPARE(int(oauthReply.error().code()), errorCode); QCOMPARE(oauthReply.accessToken(), accessToken.toUtf8()); } void FunctionalTests::testAccountData_data() { QTest::addColumn("reply"); QTest::addColumn("accountId"); QTest::addColumn("displayName"); QTest::addColumn("serviceId"); QTest::addColumn("authenticationMethod"); QTest::addColumn("settings"); QTest::newRow("empty account") << "ret = [(1, {})]" << 1 << "" << "" << 0 << QVariantMap(); QTest::newRow("no settings") << "ret = [(3, {" " 'displayName': 'Bob'," " 'serviceId': 'MyService'," " 'authMethod': 1," "})]" << 3 << "Bob" << "MyService" << 1 << QVariantMap(); QVariantMap settings; settings.insert("Host", "example.com"); settings.insert("Port", int(7000)); QTest::newRow("with settings") << "ret = [(4, {" " 'displayName': 'Tom'," " 'serviceId': 'MyService'," " 'authMethod': 2," " 'settings/Host': 'example.com'," " 'settings/Port': 7000," "})]" << 4 << "Tom" << "MyService" << 2 << settings; } void FunctionalTests::testAccountData() { QFETCH(QString, reply); QFETCH(int, accountId); QFETCH(QString, displayName); QFETCH(QString, serviceId); QFETCH(int, authenticationMethod); QFETCH(QVariantMap, settings); addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", reply); OnlineAccounts::Manager manager("my-app"); manager.waitForReady(); QList accounts = manager.availableAccounts(); QCOMPARE(accounts.count(), 1); OnlineAccounts::Account *account = accounts.first(); QVERIFY(account); QVERIFY(account->isValid()); QCOMPARE(int(account->id()), accountId); QCOMPARE(account->displayName(), displayName); QCOMPARE(account->serviceId(), serviceId); QCOMPARE(int(account->authenticationMethod()), authenticationMethod); QVariantMap accountSettings; Q_FOREACH(const QString &key, account->keys()) { accountSettings.insert(key, account->setting(key)); } QCOMPARE(accountSettings, settings); delete account; } void FunctionalTests::testPendingCallWatcher() { addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []"); addMockedMethod("RequestAccess", "sa{sv}", "(ua{sv})a{sv}", "ret = ((1, {'displayName': 'Bob'}),{})"); OnlineAccounts::Manager manager("my-app"); manager.waitForReady(); OnlineAccounts::OAuth2Data oauth; oauth.setClientId("happy app"); OnlineAccounts::PendingCall call = manager.requestAccess("my-service", oauth); // Test also the PendingCall assignment operator OnlineAccounts::PendingCall otherCall(call); call = otherCall; QVERIFY(!call.isFinished()); QVERIFY(!otherCall.isFinished()); OnlineAccounts::PendingCallWatcher *watcher = new OnlineAccounts::PendingCallWatcher(otherCall); QSignalSpy finished(watcher, SIGNAL(finished())); QVERIFY(finished.wait()); QCOMPARE(finished.count(), 1); QVERIFY(call.isFinished()); QVERIFY(otherCall.isFinished()); delete watcher; } void FunctionalTests::testAccountChanges() { addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []"); OnlineAccounts::Manager manager("my-app"); QSignalSpy accountAvailable(&manager, SIGNAL(accountAvailable(OnlineAccounts::Account*))); manager.waitForReady(); QVariantMap changes; changes.insert(ONLINE_ACCOUNTS_INFO_KEY_CHANGE_TYPE, uint(ONLINE_ACCOUNTS_INFO_CHANGE_ENABLED)); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "John"); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "coolService"); emitAccountChanged("coolService", 5, changes); QVERIFY(accountAvailable.wait()); QCOMPARE(accountAvailable.count(), 1); OnlineAccounts::Account *account = accountAvailable.at(0).at(0).value(); QSignalSpy changed(account, SIGNAL(changed())); QSignalSpy disabled(account, SIGNAL(disabled())); QVERIFY(account); QVERIFY(account->isValid()); QCOMPARE(account->id(), OnlineAccounts::AccountId(5)); QCOMPARE(account->displayName(), QString("John")); QCOMPARE(account->serviceId(), QString("coolService")); /* Now change some of the account data */ accountAvailable.clear(); changes.clear(); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_CHANGE_TYPE, uint(ONLINE_ACCOUNTS_INFO_CHANGE_UPDATED)); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "Bob"); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "coolService"); emitAccountChanged("coolService", 5, changes); QVERIFY(changed.wait()); QCOMPARE(accountAvailable.count(), 0); QCOMPARE(changed.count(), 1); QCOMPARE(disabled.count(), 0); QVERIFY(account->isValid()); QCOMPARE(account->id(), OnlineAccounts::AccountId(5)); QCOMPARE(account->displayName(), QString("Bob")); QCOMPARE(account->serviceId(), QString("coolService")); /* Now disable the account */ changed.clear(); changes.clear(); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_CHANGE_TYPE, uint(ONLINE_ACCOUNTS_INFO_CHANGE_DISABLED)); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "Bob"); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "coolService"); emitAccountChanged("coolService", 5, changes); QVERIFY(disabled.wait()); QCOMPARE(accountAvailable.count(), 0); QCOMPARE(changed.count(), 0); QCOMPARE(disabled.count(), 1); QVERIFY(!account->isValid()); } void FunctionalTests::testAuthentication() { addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = [" "(1, {" " 'displayName': 'Bob'," " 'serviceId': 'MyService0'," " 'authMethod': 1," "})," "(2, {" " 'displayName': 'Tom'," " 'serviceId': 'MyService1'," " 'authMethod': 2," "})," "(3, {" " 'displayName': 'Sam'," " 'serviceId': 'MyService2'," " 'authMethod': 3," "})," "(4, {" " 'displayName': 'Jim'," " 'serviceId': 'MyService3'," " 'authMethod': 4," "})," "]"); addMockedMethod("Authenticate", "usbba{sv}", "a{sv}", "if args[0] == 1:\n" " ret = {" " 'ConsumerKey': args[4]['ConsumerKey']," " 'ConsumerSecret': args[4]['ConsumerSecret']," " 'Token': 'a token'," " 'TokenSecret': 'a token secret'," " 'SignatureMethod': 'PLAIN'," " }\n" "elif args[0] == 2:\n" " ret = {" " 'AccessToken': 'my token'," " 'ExpiresIn': 3600," " 'GrantedScopes': args[4]['Scopes']," " }\n" "elif args[0] == 3:\n" " ret = {" " 'Username': 'admin'," " 'Password': 'rootme'," " }\n" "elif args[0] == 4:\n" " ret = {" " 'Response': 'pong'," " 'ChosenMechanism': 'tennis'," " 'state': 1," " }\n" "else:\n" " ret = {}"); OnlineAccounts::Manager manager("my-app"); manager.waitForReady(); /* Test OAuth 1.0 */ OnlineAccounts::Account *account = manager.account(1); QVERIFY(account); QCOMPARE(account->authenticationMethod(), OnlineAccounts::AuthenticationMethodOAuth1); OnlineAccounts::OAuth1Data oauth1data; oauth1data.setInteractive(false); oauth1data.setConsumerKey("a key"); QCOMPARE(oauth1data.consumerKey(), QByteArray("a key")); oauth1data.setConsumerSecret("a secret"); QCOMPARE(oauth1data.consumerSecret(), QByteArray("a secret")); OnlineAccounts::OAuth1Reply oauth1reply(account->authenticate(oauth1data)); QCOMPARE(oauth1reply.consumerKey(), QByteArray("a key")); QCOMPARE(oauth1reply.consumerSecret(), QByteArray("a secret")); QCOMPARE(oauth1reply.token(), QByteArray("a token")); QCOMPARE(oauth1reply.tokenSecret(), QByteArray("a token secret")); QCOMPARE(oauth1reply.signatureMethod(), QByteArray("PLAIN")); /* Compare the whole data dictionary */ QVariantMap expectedData; expectedData.insert(ONLINE_ACCOUNTS_AUTH_KEY_CONSUMER_KEY, "a key"); expectedData.insert(ONLINE_ACCOUNTS_AUTH_KEY_CONSUMER_SECRET, "a secret"); expectedData.insert(ONLINE_ACCOUNTS_AUTH_KEY_TOKEN, "a token"); expectedData.insert(ONLINE_ACCOUNTS_AUTH_KEY_TOKEN_SECRET, "a token secret"); expectedData.insert(ONLINE_ACCOUNTS_AUTH_KEY_SIGNATURE_METHOD, "PLAIN"); QCOMPARE(oauth1reply.data(), expectedData); /* Test OAuth 2.0 */ account = manager.account(2); QVERIFY(account); QCOMPARE(account->authenticationMethod(), OnlineAccounts::AuthenticationMethodOAuth2); OnlineAccounts::OAuth2Data oauth2data; oauth2data.invalidateCachedReply(); QVERIFY(oauth2data.mustInvalidateCachedReply()); oauth2data.setClientId("a client"); QCOMPARE(oauth2data.clientId(), QByteArray("a client")); oauth2data.setClientSecret("a secret"); QCOMPARE(oauth2data.clientSecret(), QByteArray("a secret")); QList scopes = QList() << "one" << "two" << "three"; oauth2data.setScopes(scopes); QCOMPARE(oauth2data.scopes(), scopes); OnlineAccounts::OAuth2Reply oauth2reply(account->authenticate(oauth2data)); QCOMPARE(oauth2reply.accessToken(), QByteArray("my token")); QCOMPARE(oauth2reply.expiresIn(), 3600); QCOMPARE(oauth2reply.grantedScopes(), scopes); /* Test SASL */ account = manager.account(4); QVERIFY(account); QCOMPARE(account->authenticationMethod(), OnlineAccounts::AuthenticationMethodSasl); OnlineAccounts::SaslData sasldata; OnlineAccounts::SaslReply saslreply(account->authenticate(sasldata)); QCOMPARE(saslreply.chosenMechanism(), QString("tennis")); QCOMPARE(saslreply.response(), QByteArray("pong")); QCOMPARE(saslreply.state(), OnlineAccounts::SaslReply::Continue); /* Test Password */ account = manager.account(3); QVERIFY(account); QCOMPARE(account->authenticationMethod(), OnlineAccounts::AuthenticationMethodPassword); OnlineAccounts::PasswordData pwdata; OnlineAccounts::PasswordReply pwreply(account->authenticate(pwdata)); QCOMPARE(pwreply.username(), QByteArray("admin")); QCOMPARE(pwreply.password(), QByteArray("rootme")); /* Test the copy constructor */ OnlineAccounts::OAuth2Data copy(oauth2data); QCOMPARE(copy.clientId(), QByteArray("a client")); /* Trigger the copy on write */ copy.setClientId("new client"); QCOMPARE(copy.clientId(), QByteArray("new client")); QCOMPARE(oauth2data.clientId(), QByteArray("a client")); } void FunctionalTests::testAuthenticationErrors_data() { QTest::addColumn("reply"); QTest::addColumn("errorCode"); QTest::addColumn("errorMessage"); QTest::newRow("random dbus error") << "raise dbus.exceptions.DBusException('not foobarized', name='org.foo.bar')" << int(OnlineAccounts::Error::PermissionDenied) << "not foobarized"; QTest::newRow("no account") << "raise dbus.exceptions.DBusException('Not there'," "name='" ONLINE_ACCOUNTS_ERROR_NO_ACCOUNT "')" << int(OnlineAccounts::Error::NoAccount) << "Not there"; QTest::newRow("user canceled") << "raise dbus.exceptions.DBusException('Sorry'," "name='" ONLINE_ACCOUNTS_ERROR_USER_CANCELED "')" << int(OnlineAccounts::Error::UserCanceled) << "Sorry"; QTest::newRow("permission denied") << "raise dbus.exceptions.DBusException('Nope'," "name='" ONLINE_ACCOUNTS_ERROR_PERMISSION_DENIED "')" << int(OnlineAccounts::Error::PermissionDenied) << "Nope"; QTest::newRow("Interaction required") << "raise dbus.exceptions.DBusException('Ask the user'," "name='" ONLINE_ACCOUNTS_ERROR_INTERACTION_REQUIRED "')" << int(OnlineAccounts::Error::InteractionRequired) << "Ask the user"; } void FunctionalTests::testAuthenticationErrors() { QFETCH(QString, reply); QFETCH(int, errorCode); QFETCH(QString, errorMessage); addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = [(1, {" " 'displayName': 'Bob'," " 'serviceId': 'MyService0'," " 'authMethod': 2," "})]"); addMockedMethod("Authenticate", "usbba{sv}", "a{sv}", reply); OnlineAccounts::Manager manager("my-app"); manager.waitForReady(); OnlineAccounts::Account *account = manager.account(1); QVERIFY(account); OnlineAccounts::OAuth2Data oauth2data; oauth2data.setClientId("a client"); oauth2data.setClientSecret("a secret"); oauth2data.setScopes(QList() << "one" << "two"); OnlineAccounts::OAuth2Reply r(account->authenticate(oauth2data)); QVERIFY(r.hasError()); QCOMPARE(int(r.error().code()), errorCode); QCOMPARE(r.error().text(), errorMessage); } QTEST_MAIN(FunctionalTests) #include "functional_tests.moc" online-accounts-api-0.1+16.04.20160212/tests/lib/OnlineAccounts/tst_authentication_data/0000755000015600001650000000000012657307121031322 5ustar pbuserpbgroup00000000000000././@LongLink0000000000000000000000000000016400000000000011216 Lustar 00000000000000online-accounts-api-0.1+16.04.20160212/tests/lib/OnlineAccounts/tst_authentication_data/tst_authentication_data.cpponline-accounts-api-0.1+16.04.20160212/tests/lib/OnlineAccounts/tst_authentication_data/tst_authenti0000644000015600001650000000366212657306726034001 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include #include #include "authentication_data.h" using namespace OnlineAccounts; class AuthenticationDataTest : public QObject { Q_OBJECT private Q_SLOTS: void testData(); }; void AuthenticationDataTest::testData() { OAuth2Data oauth2; oauth2.setClientId("client"); QCOMPARE(oauth2.clientId(), QByteArray("client")); oauth2.setInteractive(false); QCOMPARE(oauth2.interactive(), false); OAuth2Data copy = oauth2; QCOMPARE(copy.clientId(), QByteArray("client")); QCOMPARE(copy.interactive(), false); oauth2.setClientId("client-changed"); QCOMPARE(oauth2.clientId(), QByteArray("client-changed")); QCOMPARE(copy.clientId(), QByteArray("client")); /* As dictionary */ QVariantMap expectedParameters; expectedParameters.insert("ClientId", "client-changed"); QCOMPARE(oauth2.parameters(), expectedParameters); QVariantMap parameters; parameters.insert("UnknownKey", "some value"); parameters.insert("Hello", "World"); oauth2.setParameters(parameters); QCOMPARE(oauth2.parameters(), parameters); } QTEST_MAIN(AuthenticationDataTest) #include "tst_authentication_data.moc" ././@LongLink0000000000000000000000000000014700000000000011217 Lustar 00000000000000online-accounts-api-0.1+16.04.20160212/tests/lib/OnlineAccounts/tst_authentication_data/CMakeLists.txtonline-accounts-api-0.1+16.04.20160212/tests/lib/OnlineAccounts/tst_authentication_data/CMakeLists.t0000644000015600001650000000066012657306726033522 0ustar pbuserpbgroup00000000000000set(TEST tst_authentication_data) set(SOURCES ${OnlineAccountsQt_SOURCE_DIR}/authentication_data.cpp tst_authentication_data.cpp ) add_executable(${TEST} ${SOURCES}) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${OnlineAccountsQt_SOURCE_DIR} ${OnlineAccountsDaemon_SOURCE_DIR}/.. ) qt5_use_modules(${TEST} Core DBus Test) add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) add_dependencies(check ${TEST}) online-accounts-api-0.1+16.04.20160212/tests/lib/OnlineAccounts/CMakeLists.txt0000644000015600001650000000011512657306726027167 0ustar pbuserpbgroup00000000000000add_subdirectory(functional_tests) add_subdirectory(tst_authentication_data) online-accounts-api-0.1+16.04.20160212/tests/lib/qml_module/0000755000015600001650000000000012657307121023632 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/tests/lib/qml_module/tst_qml_module.cpp0000644000015600001650000005125512657306740027404 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsModule * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "OnlineAccountsDaemon/dbus_constants.h" #include #include #include #include #include #include #include #include #include #include #include namespace QTest { template<> char *toString(const QVariantMap &map) { QJsonDocument doc(QJsonObject::fromVariantMap(map)); return qstrdup(doc.toJson(QJsonDocument::Compact).data()); } } // QTest namespace class ModuleTest: public QObject { Q_OBJECT public: ModuleTest(); OrgFreedesktopDBusMockInterface &mocked() { return m_mock.mockInterface(ONLINE_ACCOUNTS_MANAGER_SERVICE_NAME, ONLINE_ACCOUNTS_MANAGER_PATH, ONLINE_ACCOUNTS_MANAGER_INTERFACE, QDBusConnection::SessionBus); } void addMockedMethod(const QString &name, const QString &in_sig, const QString &out_sig, const QString &code) { return mocked().AddMethod(ONLINE_ACCOUNTS_MANAGER_INTERFACE, name, in_sig, out_sig, code).waitForFinished(); } void emitAccountChanged(const QString &service, uint accountId, const QVariantMap &changes) { QVariantList args; args << service; QDBusArgument info; info.beginStructure(); info << accountId << changes; info.endStructure(); args << QVariant::fromValue(info); mocked().EmitSignal(ONLINE_ACCOUNTS_MANAGER_INTERFACE, "AccountChanged", "s(ua{sv})", args); } QVariant get(const QAbstractListModel *model, int row, QString roleName) { QHash roleNames = model->roleNames(); int role = roleNames.key(roleName.toLatin1(), -1); return model->data(model->index(row), role); } private Q_SLOTS: void initTestCase(); void testModuleImport(); void testModelProperties(); void testModelRoles_data(); void testModelRoles(); void testModelFilters_data(); void testModelFilters(); void testModelChanges(); void testModelRequestAccess_data(); void testModelRequestAccess(); void testAccountAuthentication_data(); void testAccountAuthentication(); void testInitialization_data(); void testInitialization(); private: QtDBusTest::DBusTestRunner m_dbus; QtDBusMock::DBusMock m_mock; }; ModuleTest::ModuleTest(): QObject(), m_mock(m_dbus) { m_mock.registerCustomMock(ONLINE_ACCOUNTS_MANAGER_SERVICE_NAME, ONLINE_ACCOUNTS_MANAGER_PATH, ONLINE_ACCOUNTS_MANAGER_INTERFACE, QDBusConnection::SessionBus); m_dbus.startServices(); } void ModuleTest::initTestCase() { qputenv("QML2_IMPORT_PATH", TEST_QML_IMPORT_PATH); } void ModuleTest::testModuleImport() { QQmlEngine engine; QQmlComponent component(&engine); component.setData("import Ubuntu.OnlineAccounts 2.0\n" "AccountModel {}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); delete object; } void ModuleTest::testModelProperties() { QQmlEngine engine; QQmlComponent component(&engine); component.setData("import Ubuntu.OnlineAccounts 2.0\n" "AccountModel {}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QVERIFY(object->setProperty("applicationId", "foo")); QCOMPARE(object->property("applicationId").toString(), QString("foo")); QVERIFY(object->setProperty("serviceId", "bar")); QCOMPARE(object->property("serviceId").toString(), QString("bar")); QCOMPARE(object->property("ready").toBool(), false); delete object; } void ModuleTest::testModelRoles_data() { QTest::addColumn("accountData"); QTest::addColumn("displayName"); QTest::addColumn("serviceId"); QTest::addColumn("authenticationMethod"); QTest::addColumn("settings"); QVariantMap settings; QTest::newRow("empty") << "{}" << "" << "" << 0 << settings; settings.insert("Server", "www.example.com"); settings.insert("Port", "9900"); QTest::newRow("complete") << "{" " '" ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME "': 'Tom'," " '" ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID "': 'cool'," " '" ONLINE_ACCOUNTS_INFO_KEY_AUTH_METHOD "': 2," " '" ONLINE_ACCOUNTS_INFO_KEY_SETTINGS "Server': 'www.example.com'," " '" ONLINE_ACCOUNTS_INFO_KEY_SETTINGS "Port': 9900," "}" << "Tom" << "cool" << 2 << settings; } void ModuleTest::testModelRoles() { QFETCH(QString, accountData); QFETCH(QString, displayName); QFETCH(QString, serviceId); QFETCH(int, authenticationMethod); QFETCH(QVariantMap, settings); addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", QString("ret = [(1, %1)]").arg(accountData)); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import Ubuntu.OnlineAccounts 2.0\n" "AccountModel { applicationId: \"foo\" }", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QAbstractListModel *model = qobject_cast(object); QVERIFY(model != 0); QCOMPARE(object->property("ready").toBool(), false); QSignalSpy ready(object, SIGNAL(isReadyChanged())); ready.wait(); QCOMPARE(object->property("ready").toBool(), true); QCOMPARE(model->rowCount(), 1); QCOMPARE(model->data(model->index(0), Qt::DisplayRole).toString(), QString("%1 - %2").arg(displayName).arg(serviceId)); QCOMPARE(get(model, 0, "displayName").toString(), displayName); QCOMPARE(get(model, 0, "valid").toBool(), true); QCOMPARE(get(model, 0, "accountId").toInt(), 1); QCOMPARE(get(model, 0, "serviceId").toString(), serviceId); QCOMPARE(get(model, 0, "authenticationMethod").toInt(), authenticationMethod); // until https://bugs.launchpad.net/bugs/1479768 is fixed QCOMPARE(get(model, 0, "settings").toMap(), settings); QObject *account = get(model, 0, "account").value(); QVERIFY(account != 0); QCOMPARE(account->metaObject()->className(), "OnlineAccountsModule::Account"); QCOMPARE(account, model->property("accountList").value >().first()); delete object; } void ModuleTest::testModelFilters_data() { QTest::addColumn("reply"); QTest::addColumn("filters"); QTest::addColumn >("expectedIds"); QTest::addColumn("expectedDisplayNames"); QTest::newRow("no accounts") << "ret = []" << "" << QList(); QTest::newRow("one account, no service filter") << "ret = [(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]" << "" << (QList() << 1); QTest::newRow("one account, with service filter") << "ret = [(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]" << "serviceId: \"bar\"" << QList(); } void ModuleTest::testModelFilters() { QFETCH(QString, reply); QFETCH(QString, filters); QFETCH(QList, expectedIds); addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", reply); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import Ubuntu.OnlineAccounts 2.0\n" "AccountModel {\n" " applicationId: \"foo\";" + filters.toUtf8() + "\n" "}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QAbstractListModel *model = qobject_cast(object); QVERIFY(model != 0); QTRY_COMPARE(model->property("count").toInt(), expectedIds.count()); QList ids; QStringList displayNames; for (int i = 0; i < expectedIds.count(); i++) { ids.append(get(model, i, "accountId").toInt()); } QCOMPARE(ids, expectedIds); delete object; } void ModuleTest::testModelChanges() { addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []"); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import Ubuntu.OnlineAccounts 2.0\n" "AccountModel { applicationId: \"foo\" }", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QAbstractListModel *model = qobject_cast(object); QVERIFY(model != 0); QSignalSpy countChanged(model, SIGNAL(countChanged())); QSignalSpy dataChanged(model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&))); QVariantMap changes; changes.insert(ONLINE_ACCOUNTS_INFO_KEY_CHANGE_TYPE, uint(ONLINE_ACCOUNTS_INFO_CHANGE_ENABLED)); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "John"); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "coolService"); emitAccountChanged("coolService", 5, changes); QVERIFY(countChanged.wait()); QCOMPARE(dataChanged.count(), 0); QTRY_COMPARE(model->rowCount(), 1); QCOMPARE(model->property("accountList").value().count(), 1); QCOMPARE(get(model, 0, "displayName").toString(), QString("John")); QObject *account = model->property("accountList").value().first(); QSignalSpy accountChanged(account, SIGNAL(accountChanged())); QSignalSpy validChanged(account, SIGNAL(validChanged())); QVERIFY(account); QVERIFY(account->property("valid").toBool()); QCOMPARE(account->property("displayName").toString(), QString("John")); countChanged.clear(); // Change the display name changes.clear(); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_CHANGE_TYPE, uint(ONLINE_ACCOUNTS_INFO_CHANGE_UPDATED)); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "Bob"); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "coolService"); emitAccountChanged("coolService", 5, changes); QVERIFY(dataChanged.wait()); QCOMPARE(dataChanged.count(), 1); QCOMPARE(countChanged.count(), 0); QCOMPARE(accountChanged.count(), 1); QCOMPARE(validChanged.count(), 0); QCOMPARE(get(model, 0, "displayName").toString(), QString("Bob")); dataChanged.clear(); accountChanged.clear(); // disable the account changes.clear(); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_CHANGE_TYPE, uint(ONLINE_ACCOUNTS_INFO_CHANGE_DISABLED)); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "Bob"); changes.insert(ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "coolService"); emitAccountChanged("coolService", 5, changes); QVERIFY(countChanged.wait()); QCOMPARE(countChanged.count(), 1); QCOMPARE(accountChanged.count(), 0); QCOMPARE(validChanged.count(), 1); QCOMPARE(model->rowCount(), 0); QCOMPARE(model->property("accountList").value().count(), 0); QCOMPARE(account->property("valid").toBool(), false); delete object; } void ModuleTest::testModelRequestAccess_data() { QTest::addColumn("reply"); QTest::addColumn("expectedAccessReply"); QTest::addColumn("expectedAuthenticationData"); QVariantMap accessReply; QVariantMap authenticationData; accessReply["errorCode"] = 4; accessReply["errorText"] = "('org.foo.bar', 'not foobarized')"; QTest::newRow("dbus error") << "raise dbus.exceptions.DBusException('org.foo.bar', 'not foobarized')" << accessReply << authenticationData; accessReply.clear(); accessReply["accountDisplayName"] = "Bob"; authenticationData.clear(); authenticationData.insert("AccessToken", "GoOn"); QTest::newRow("access granted") << "ret = ((1, {'displayName': 'Bob'}),{'AccessToken':'GoOn'})" << accessReply << authenticationData; } void ModuleTest::testModelRequestAccess() { QFETCH(QString, reply); QFETCH(QVariantMap, expectedAccessReply); QFETCH(QVariantMap, expectedAuthenticationData); addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = [(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]"); addMockedMethod("RequestAccess", "sa{sv}", "(ua{sv})a{sv}", reply); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import Ubuntu.OnlineAccounts 2.0\n" "AccountModel {\n" " applicationId: \"foo\"\n" "}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QAbstractListModel *model = qobject_cast(object); QVERIFY(model != 0); QSignalSpy accessReplySpy(model, SIGNAL(accessReply(const QVariantMap&,const QVariantMap&))); QString serviceId = "bar"; QVariantMap params; bool ok = QMetaObject::invokeMethod(model, "requestAccess", Q_ARG(QString, serviceId), Q_ARG(QVariantMap, params)); QVERIFY(ok); QVERIFY(accessReplySpy.wait()); QVariantMap accessReply = accessReplySpy.at(0).at(0).toMap(); QVariantMap authenticationData = accessReplySpy.at(0).at(1).toMap(); if (expectedAccessReply.contains("accountDisplayName")) { QObject *account = accessReply["account"].value(); QVERIFY(account != 0); QCOMPARE(account->metaObject()->className(), "OnlineAccountsModule::Account"); QCOMPARE(account->property("displayName").toString(), expectedAccessReply["accountDisplayName"].toString()); } else { QCOMPARE(accessReply, expectedAccessReply); } QCOMPARE(authenticationData, expectedAuthenticationData); delete object; } void ModuleTest::testAccountAuthentication_data() { QTest::addColumn("authMethod"); QTest::addColumn("reply"); QTest::addColumn("params"); QTest::addColumn("expectedAuthenticationData"); QVariantMap params; QVariantMap authenticationData; authenticationData["errorCode"] = 4; authenticationData["errorText"] = "not foobarized"; QTest::newRow("random dbus error") << ONLINE_ACCOUNTS_AUTH_METHOD_OAUTH1 << "raise dbus.exceptions.DBusException('not foobarized', name='org.foo.bar')" << params << authenticationData; authenticationData["errorCode"] = 1; authenticationData["errorText"] = "Not there"; QTest::newRow("no account") << ONLINE_ACCOUNTS_AUTH_METHOD_OAUTH1 << "raise dbus.exceptions.DBusException('Not there'," "name='" ONLINE_ACCOUNTS_ERROR_NO_ACCOUNT "')" << params << authenticationData; authenticationData["errorCode"] = 3; authenticationData["errorText"] = "Sorry"; QTest::newRow("user canceled") << ONLINE_ACCOUNTS_AUTH_METHOD_OAUTH1 << "raise dbus.exceptions.DBusException('Sorry'," "name='" ONLINE_ACCOUNTS_ERROR_USER_CANCELED "')" << params << authenticationData; params["ConsumerKey"] = "aaaa"; params["ConsumerSecret"] = "bbb"; authenticationData = params; authenticationData["Token"] = "a token"; authenticationData["TokenSecret"] = "a token secret"; authenticationData["SignatureMethod"] = "PLAIN"; QTest::newRow("oauth 1.0") << ONLINE_ACCOUNTS_AUTH_METHOD_OAUTH1 << "ret = {" " 'ConsumerKey': args[4]['ConsumerKey']," " 'ConsumerSecret': args[4]['ConsumerSecret']," " 'Token': 'a token'," " 'TokenSecret': 'a token secret'," " 'SignatureMethod': 'PLAIN'," "}" << params << authenticationData; params.clear(); authenticationData.clear(); params["ClientId"] = "aaaa"; params["ClientSecret"] = "bbb"; params["Scopes"] = (QStringList() << "one" << "two"); authenticationData["AccessToken"] = "my token"; authenticationData["ExpiresIn"] = 3600; authenticationData["GrantedScopes"] = (QStringList() << "one" << "two"); QTest::newRow("oauth 2.0") << ONLINE_ACCOUNTS_AUTH_METHOD_OAUTH2 << "ret = {" " 'AccessToken': 'my token'," " 'ExpiresIn': 3600," " 'GrantedScopes': args[4]['Scopes']," "}" << params << authenticationData; params.clear(); authenticationData.clear(); authenticationData["Username"] = "admin"; authenticationData["Password"] = "rootme"; QTest::newRow("password") << ONLINE_ACCOUNTS_AUTH_METHOD_PASSWORD << "ret = {" " 'Username': 'admin'," " 'Password': 'rootme'," "}" << params << authenticationData; } void ModuleTest::testAccountAuthentication() { QFETCH(int, authMethod); QFETCH(QString, reply); QFETCH(QVariantMap, params); QFETCH(QVariantMap, expectedAuthenticationData); addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", QString("ret = [(1, {" " 'displayName': 'Bob'," " 'serviceId': 'MyService0'," " 'authMethod': %1," "})]").arg(authMethod)); addMockedMethod("Authenticate", "usbba{sv}", "a{sv}", reply); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import Ubuntu.OnlineAccounts 2.0\n" "AccountModel {\n" " applicationId: \"foo\"\n" "}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QAbstractListModel *model = qobject_cast(object); QVERIFY(model != 0); QTRY_COMPARE(model->rowCount(), 1); QObject *account = model->property("accountList").value().first(); QSignalSpy authenticationReply(account, SIGNAL(authenticationReply(const QVariantMap&))); bool ok = QMetaObject::invokeMethod(account, "authenticate", Q_ARG(QVariantMap, params)); QVERIFY(ok); QVERIFY(authenticationReply.wait()); QVariantMap authenticationData = authenticationReply.at(0).at(0).toMap(); QCOMPARE(authenticationData, expectedAuthenticationData); delete object; } void ModuleTest::testInitialization_data() { QTest::addColumn("appId"); QTest::addColumn("errorExpected"); QTest::newRow("empty APP_ID") << "" << true; QTest::newRow("invalid APP_ID") << "" << true; QTest::newRow("valid APP_ID") << "my.package_app_0.2" << false; } void ModuleTest::testInitialization() { QFETCH(QString, appId); QFETCH(bool, errorExpected); qputenv("APP_ID", appId.toUtf8()); if (errorExpected) { QTest::ignoreMessage(QtWarningMsg, QRegularExpression("Ubuntu.OnlineAccounts:.*")); } QQmlEngine engine; QQmlComponent component(&engine); component.setData("import Ubuntu.OnlineAccounts 2.0\n" "AccountModel {}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); if (!errorExpected) { /* We just want to check that invoking this method won't cause a crash */ QString serviceId = "bar"; QVariantMap params; bool ok = QMetaObject::invokeMethod(object, "requestAccess", Q_ARG(QString, serviceId), Q_ARG(QVariantMap, params)); QVERIFY(ok); } delete object; } QTEST_MAIN(ModuleTest) #include "tst_qml_module.moc" online-accounts-api-0.1+16.04.20160212/tests/lib/qml_module/CMakeLists.txt0000644000015600001650000000124312657306726026404 0ustar pbuserpbgroup00000000000000set(TEST tst_qml_module) set(SOURCES tst_qml_module.cpp ) pkg_check_modules(QTDBUSMOCK REQUIRED libqtdbusmock-1) pkg_check_modules(QTDBUSTEST REQUIRED libqtdbustest-1) add_executable(${TEST} ${SOURCES}) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${OnlineAccountsDaemon_SOURCE_DIR}/.. ${QTDBUSMOCK_INCLUDE_DIRS} ${QTDBUSTEST_INCLUDE_DIRS} ) target_link_libraries(${TEST} ${QTDBUSMOCK_LIBRARIES} ${QTDBUSTEST_LIBRARIES} ) add_definitions( -DTEST_QML_IMPORT_PATH="${OnlineAccountsQML_BINARY_DIR}/../.." ) qt5_use_modules(${TEST} Core DBus Qml Test) add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) add_dependencies(check ${TEST}) online-accounts-api-0.1+16.04.20160212/tests/CMakeLists.txt0000644000015600001650000000042312657306726023477 0ustar pbuserpbgroup00000000000000set(XVFB_COMMAND) find_program(XVFBRUN xvfb-run) if(XVFBRUN) set(XVFB_COMMAND ${XVFBRUN} -s "-screen 0 640x480x24" -a) else() message(WARNING "Cannot find xvfb-run.") endif() add_subdirectory(daemon) add_subdirectory(lib/OnlineAccounts) add_subdirectory(lib/qml_module) online-accounts-api-0.1+16.04.20160212/src/0000755000015600001650000000000012657307121020353 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/src/daemon/0000755000015600001650000000000012657307121021616 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/src/daemon/main.cpp0000644000015600001650000000455312657306726023267 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include #include #include #include "inactivity_timer.h" #include "OnlineAccountsDaemon/Manager" int main(int argc, char **argv) { QCoreApplication app(argc, argv); QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); /* default daemonTimeout to 5 seconds */ int daemonTimeout = 5; /* override daemonTimeout if OAU_DAEMON_TIMEOUT is set */ if (environment.contains(QLatin1String("OAD_TIMEOUT"))) { bool isOk; int value = environment.value( QLatin1String("OAD_TIMEOUT")).toInt(&isOk); if (isOk) daemonTimeout = value; } auto manager = (QObject *)oad_create_manager(0); auto inactivityTimer = new OnlineAccountsDaemon::InactivityTimer(daemonTimeout * 1000); inactivityTimer->watchObject(manager); QObject::connect(inactivityTimer, SIGNAL(timeout()), &app, SLOT(quit())); QDBusConnection bus = QDBusConnection::sessionBus(); bus.registerObject("/com/ubuntu/OnlineAccounts/Manager", manager); bus.registerService("com.ubuntu.OnlineAccounts.Manager"); bus.connect(QString(), QStringLiteral("/org/freedesktop/DBus/Local"), QStringLiteral("org.freedesktop.DBus.Local"), QStringLiteral("Disconnected"), manager, SLOT(onDisconnected())); int ret = app.exec(); bus.unregisterService("com.ubuntu.OnlineAccounts.Manager"); bus.unregisterObject("/com/ubuntu/OnlineAccounts/Manager"); delete inactivityTimer; delete manager; return ret; } online-accounts-api-0.1+16.04.20160212/src/daemon/com.ubuntu.OnlineAccounts.Manager.service.in0000644000015600001650000000014512657306726032212 0ustar pbuserpbgroup00000000000000[D-BUS Service] Name=com.ubuntu.OnlineAccounts.Manager Exec=${CMAKE_INSTALL_FULL_BINDIR}/${ACCOUNTD} online-accounts-api-0.1+16.04.20160212/src/daemon/inactivity_timer.cpp0000644000015600001650000000341112657306726025716 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2013-2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This file is part of OnlineAccountsDaemon * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . */ #include "inactivity_timer.h" #include using namespace OnlineAccountsDaemon; InactivityTimer::InactivityTimer(int interval, QObject *parent): QObject(parent), m_interval(interval) { m_timer.setSingleShot(true); QObject::connect(&m_timer, SIGNAL(timeout()), this, SLOT(onTimeout())); } void InactivityTimer::watchObject(QObject *object) { connect(object, SIGNAL(isIdleChanged()), SLOT(onIdleChanged())); m_watchedObjects.append(object); /* Force an initial check */ onIdleChanged(); } void InactivityTimer::onIdleChanged() { if (allObjectsAreIdle()) { m_timer.start(m_interval); } else { m_timer.stop(); } } void InactivityTimer::onTimeout() { if (allObjectsAreIdle()) { Q_EMIT timeout(); } } bool InactivityTimer::allObjectsAreIdle() const { Q_FOREACH(const QObject *object, m_watchedObjects) { if (!object->property("isIdle").toBool()) { return false; } } return true; } online-accounts-api-0.1+16.04.20160212/src/daemon/inactivity_timer.h0000644000015600001650000000265312657306726025372 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2013-2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This file is part of OnlineAccountsDaemon * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DAEMON_INACTIVITY_TIMER_H #define ONLINE_ACCOUNTS_DAEMON_INACTIVITY_TIMER_H #include #include #include namespace OnlineAccountsDaemon { class InactivityTimer: public QObject { Q_OBJECT public: InactivityTimer(int interval, QObject *parent = 0); ~InactivityTimer() {} void watchObject(QObject *object); Q_SIGNALS: void timeout(); private Q_SLOTS: void onIdleChanged(); void onTimeout(); private: bool allObjectsAreIdle() const; private: QList m_watchedObjects; QTimer m_timer; int m_interval; }; } // namespace #endif // ONLINE_ACCOUNTS_DAEMON_INACTIVITY_TIMER_H online-accounts-api-0.1+16.04.20160212/src/daemon/CMakeLists.txt0000644000015600001650000000117712657306726024376 0ustar pbuserpbgroup00000000000000project(accountd) set(ACCOUNTD accountd) include_directories(. ${OnlineAccountsDaemon_SOURCE_DIR}/.. ) add_executable(${ACCOUNTD} inactivity_timer.cpp main.cpp ) qt5_use_modules(${ACCOUNTD} DBus) target_link_libraries(${ACCOUNTD} OnlineAccountsDaemon ) set_target_properties(${ACCOUNTD} PROPERTIES AUTOMOC TRUE) install(TARGETS ${ACCOUNTD} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) set(SERVICE_FILE com.ubuntu.OnlineAccounts.Manager.service) configure_file(${SERVICE_FILE}.in ${SERVICE_FILE}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SERVICE_FILE} DESTINATION ${CMAKE_INSTALL_DATADIR}/dbus-1/services ) online-accounts-api-0.1+16.04.20160212/src/lib/0000755000015600001650000000000012657307121021121 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/0000755000015600001650000000000012657307121025171 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/authentication_request.cpp0000644000015600001650000000523512657306726032503 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "authentication_request.h" #include #include "authenticator.h" #include "manager_adaptor.h" using namespace OnlineAccountsDaemon; namespace OnlineAccountsDaemon { class AuthenticationRequestPrivate: public QObject { Q_OBJECT Q_DECLARE_PUBLIC(AuthenticationRequest) public: AuthenticationRequestPrivate(AuthenticationRequest *q); private Q_SLOTS: void onFinished(); private: Authenticator m_authenticator; AuthenticationRequest *q_ptr; }; } // namespace AuthenticationRequestPrivate::AuthenticationRequestPrivate(AuthenticationRequest *q): QObject(q), q_ptr(q) { QObject::connect(&m_authenticator, SIGNAL(finished()), this, SLOT(onFinished())); } void AuthenticationRequestPrivate::onFinished() { Q_Q(AuthenticationRequest); if (m_authenticator.isError()) { q->setError(m_authenticator.errorName(), m_authenticator.errorMessage()); } else { q->setReply(QList() << m_authenticator.reply()); } } AuthenticationRequest::AuthenticationRequest(const CallContext &context, QObject *parent): AsyncOperation(context, parent), d_ptr(new AuthenticationRequestPrivate(this)) { } AuthenticationRequest::~AuthenticationRequest() { delete d_ptr; } void AuthenticationRequest::setInteractive(bool interactive) { Q_D(AuthenticationRequest); d->m_authenticator.setInteractive(interactive); } void AuthenticationRequest::invalidateCache() { Q_D(AuthenticationRequest); d->m_authenticator.invalidateCache(); } void AuthenticationRequest::authenticate(const Accounts::AuthData &authData, const QVariantMap ¶meters) { Q_D(AuthenticationRequest); QVariantMap p(parameters); p.insert("requestorPid", context().clientPid()); d->m_authenticator.authenticate(authData, p); } #include "authentication_request.moc" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/manager_adaptor.cpp0000644000015600001650000001224212657306726031034 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "manager_adaptor.h" #include #include #include "client_registry.h" using namespace OnlineAccountsDaemon; QDBusArgument &operator<<(QDBusArgument &argument, const AccountInfo &info) { argument.beginStructure(); argument << info.accountId << info.details; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, AccountInfo &info) { argument.beginStructure(); argument >> info.accountId >> info.details; argument.endStructure(); return argument; } CallContext::CallContext(QDBusContext *dbusContext): m_connection(dbusContext->connection()), m_message(dbusContext->message()) { CallContextCounter::instance()->addContext(*this); } CallContext::CallContext(const CallContext &other): m_connection(other.m_connection), m_message(other.m_message) { CallContextCounter::instance()->addContext(*this); } CallContext::~CallContext() { CallContextCounter::instance()->removeContext(*this); } void CallContext::setDelayedReply(bool delayed) { m_message.setDelayedReply(delayed); } void CallContext::sendReply(const QList &args) const { m_connection.send(m_message.createReply(args)); } void CallContext::sendError(const QString &name, const QString &message) const { m_connection.send(m_message.createErrorReply(name, message)); } QString CallContext::securityContext() const { ClientRegistry *clientRegistry = ClientRegistry::instance(); QString client = clientRegistry->registerClient(m_connection, m_message); return clientRegistry->clientSecurityContext(client); } pid_t CallContext::clientPid() const { ClientRegistry *clientRegistry = ClientRegistry::instance(); return clientRegistry->clientPid(m_message.service()); } QString CallContext::clientName() const { return m_message.service(); } static CallContextCounter *m_callContextCounterInstance = 0; CallContextCounter::CallContextCounter(): QObject(), m_contexts(0) { } CallContextCounter *CallContextCounter::instance() { if (!m_callContextCounterInstance) { m_callContextCounterInstance = new CallContextCounter; } return m_callContextCounterInstance; } void CallContextCounter::addContext(const CallContext &) { m_contexts++; Q_EMIT activeContextsChanged(); } void CallContextCounter::removeContext(const CallContext &) { m_contexts--; Q_EMIT activeContextsChanged(); } namespace OnlineAccountsDaemon { class ManagerAdaptorPrivate { public: ManagerAdaptorPrivate(); private: friend class ManagerAdaptor; }; } // namespace ManagerAdaptorPrivate::ManagerAdaptorPrivate() { } ManagerAdaptor::ManagerAdaptor(Manager *parent): QDBusAbstractAdaptor(parent), d_ptr(new ManagerAdaptorPrivate) { qRegisterMetaType("AccountInfo"); qRegisterMetaType >("QList"); qDBusRegisterMetaType(); qDBusRegisterMetaType>(); setAutoRelaySignals(false); } ManagerAdaptor::~ManagerAdaptor() { delete d_ptr; } void ManagerAdaptor::notifyAccountChange(const AccountInfo &info, uint changeType) { AccountInfo copy(info); copy.details[ONLINE_ACCOUNTS_INFO_KEY_CHANGE_TYPE] = changeType; Q_EMIT AccountChanged(copy.serviceId(), copy); } QVariantMap ManagerAdaptor::Authenticate(uint accountId, const QString &serviceId, bool interactive, bool invalidate, const QVariantMap ¶meters) { parent()->authenticate(accountId, serviceId, interactive, invalidate, parameters, CallContext(dbusContext())); return QVariantMap(); } QList ManagerAdaptor::GetAccounts(const QVariantMap &filters) { return parent()->getAccounts(filters, CallContext(dbusContext())); } AccountInfo ManagerAdaptor::RequestAccess(const QString &serviceId, const QVariantMap ¶meters, QVariantMap &credentials) { parent()->requestAccess(serviceId, parameters, CallContext(dbusContext())); credentials = QVariantMap(); return AccountInfo(); } #include "manager_adaptor.moc" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/client_registry.cpp0000644000015600001650000001266212657306726031124 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "client_registry.h" #include #include #include #include #include #include #include using namespace OnlineAccountsDaemon; namespace OnlineAccountsDaemon { class ClientRegistryPrivate: public QObject { Q_OBJECT Q_DECLARE_PUBLIC(ClientRegistry) public: ClientRegistryPrivate(ClientRegistry *q); void registerClient(const QString &client); QString getSecurityContext(const QString &client) const; pid_t getPid(const QString &client) const; private Q_SLOTS: void onServiceUnregistered(const QString &client); private: static ClientRegistry *m_instance; QDBusConnection m_connection; QDBusServiceWatcher m_watcher; QHash m_clientContexts; ClientRegistry *q_ptr; }; ClientRegistry *ClientRegistryPrivate::m_instance = 0; } // namespace ClientRegistryPrivate::ClientRegistryPrivate(ClientRegistry *q): QObject(q), m_connection(QDBusConnection::sessionBus()), q_ptr(q) { m_watcher.setConnection(m_connection); QObject::connect(&m_watcher, SIGNAL(serviceUnregistered(const QString&)), this, SLOT(onServiceUnregistered(const QString&))); } void ClientRegistryPrivate::registerClient(const QString &client) { Q_Q(ClientRegistry); if (m_clientContexts.contains(client)) return; bool wasEmpty = m_clientContexts.isEmpty(); m_clientContexts.insert(client, getSecurityContext(client)); m_watcher.addWatchedService(client); if (wasEmpty) { Q_EMIT q->hasClientsChanged(); } } QString ClientRegistryPrivate::getSecurityContext(const QString &client) const { QString dbusService = qEnvironmentVariableIsEmpty("OAD_TESTING") ? "org.freedesktop.DBus" : "mocked.org.freedesktop.dbus"; QDBusMessage msg = QDBusMessage::createMethodCall(dbusService, "/org/freedesktop/DBus", "org.freedesktop.DBus", "GetConnectionAppArmorSecurityContext"); msg << client; QDBusMessage reply = m_connection.call(msg, QDBus::Block); QString context; if (reply.type() == QDBusMessage::ReplyMessage) { context = reply.arguments().value(0).value(); } else { qWarning() << "Could not determine AppArmor context: " << reply.errorName() << ": " << reply.errorMessage(); context = QStringLiteral("unconfined"); } return context; } pid_t ClientRegistryPrivate::getPid(const QString &client) const { QDBusReply reply = m_connection.interface()->servicePid(client); return pid_t(reply.value()); } void ClientRegistryPrivate::onServiceUnregistered(const QString &client) { Q_Q(ClientRegistry); qDebug() << "Client disappeared:" << client; m_clientContexts.remove(client); if (m_clientContexts.isEmpty()) { Q_EMIT q->hasClientsChanged(); } } ClientRegistry::ClientRegistry(): QObject(), d_ptr(new ClientRegistryPrivate(this)) { } ClientRegistry::~ClientRegistry() { delete d_ptr; } ClientRegistry *ClientRegistry::instance() { if (!ClientRegistryPrivate::m_instance) { ClientRegistryPrivate::m_instance = new ClientRegistry(); } return ClientRegistryPrivate::m_instance; } QString ClientRegistry::registerClient(const QDBusConnection &connection, const QDBusMessage &message) { Q_UNUSED(connection); // only needed for p2p clients QString client = message.service(); registerClient(client); return client; } void ClientRegistry::registerClient(const QString &client) { Q_D(ClientRegistry); d->registerClient(client); } QStringList ClientRegistry::clients() const { Q_D(const ClientRegistry); return d->m_clientContexts.keys(); } void ClientRegistry::registerActiveClients(const QStringList &clients) { Q_D(const ClientRegistry); QStringList activeServices = d->m_connection.interface()->registeredServiceNames().value(); Q_FOREACH(const QString &client, clients) { if (activeServices.contains(client)) { registerClient(client); } } } QString ClientRegistry::clientSecurityContext(const QString &client) const { Q_D(const ClientRegistry); QHash::const_iterator i = d->m_clientContexts.find(client); if (i != d->m_clientContexts.constEnd()) { return i.value(); } return d->getSecurityContext(client); } pid_t ClientRegistry::clientPid(const QString &client) const { Q_D(const ClientRegistry); return d->getPid(client); } #include "client_registry.moc" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/authenticator.h0000644000015600001650000000324712657306726030234 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DAEMON_AUTHENTICATOR_H #define ONLINE_ACCOUNTS_DAEMON_AUTHENTICATOR_H #include #include #include namespace Accounts { class AuthData; } namespace OnlineAccountsDaemon { class AuthenticatorPrivate; class Authenticator: public QObject { Q_OBJECT public: explicit Authenticator(QObject *parent = 0); ~Authenticator(); void setInteractive(bool interactive); void invalidateCache(); void authenticate(const Accounts::AuthData &authData, const QVariantMap ¶meters); bool isError() const { return !errorName().isEmpty(); } QVariantMap reply() const; QString errorName() const; QString errorMessage() const; Q_SIGNALS: void finished(); private: Q_DECLARE_PRIVATE(Authenticator) AuthenticatorPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_DAEMON_AUTHENTICATOR_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/access_request.h0000644000015600001650000000350112657306726030364 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DAEMON_ACCESS_REQUEST_H #define ONLINE_ACCOUNTS_DAEMON_ACCESS_REQUEST_H #include #include #include #include #include "async_operation.h" namespace Accounts { class AuthData; } namespace OnlineAccountsDaemon { class AccountInfo; class AccessRequestPrivate; class AccessRequest: public AsyncOperation { Q_OBJECT public: explicit AccessRequest(const CallContext &context, QObject *parent = 0); ~AccessRequest(); void requestAccess(const QString &applicationId, const QString &serviceId, const QVariantMap ¶meters, pid_t clientPid); void setAccountInfo(const AccountInfo &accountInfo, const Accounts::AuthData &authData); Q_SIGNALS: void loadRequest(uint accountId, const QString &serviceId); private: Q_DECLARE_PRIVATE(AccessRequest) AccessRequestPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_DAEMON_ACCESS_REQUEST_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/dbus_constants.h0000644000015600001650000000734212657306732030410 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015-2016 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DBUS_CONSTANTS_P_H #define ONLINE_ACCOUNTS_DBUS_CONSTANTS_P_H /* Manager service, object path and interface name */ #define ONLINE_ACCOUNTS_MANAGER_SERVICE_NAME \ "com.ubuntu.OnlineAccounts.Manager" #define ONLINE_ACCOUNTS_MANAGER_PATH "/com/ubuntu/OnlineAccounts/Manager" #define ONLINE_ACCOUNTS_MANAGER_INTERFACE ONLINE_ACCOUNTS_MANAGER_SERVICE_NAME /* Keys for the account info dictionary */ #define ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME "displayName" #define ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID "serviceId" #define ONLINE_ACCOUNTS_INFO_KEY_AUTH_METHOD "authMethod" # define ONLINE_ACCOUNTS_AUTH_METHOD_UNKNOWN 0 # define ONLINE_ACCOUNTS_AUTH_METHOD_OAUTH1 1 # define ONLINE_ACCOUNTS_AUTH_METHOD_OAUTH2 2 # define ONLINE_ACCOUNTS_AUTH_METHOD_PASSWORD 3 # define ONLINE_ACCOUNTS_AUTH_METHOD_SASL 4 #define ONLINE_ACCOUNTS_INFO_KEY_SETTINGS "settings/" #define ONLINE_ACCOUNTS_INFO_KEY_CHANGE_TYPE "changeType" # define ONLINE_ACCOUNTS_INFO_CHANGE_ENABLED 0 # define ONLINE_ACCOUNTS_INFO_CHANGE_DISABLED 1 # define ONLINE_ACCOUNTS_INFO_CHANGE_UPDATED 2 /* Error codes */ #define ONLINE_ACCOUNTS_ERROR_PREFIX "com.ubuntu.OnlineAccounts.Error." #define ONLINE_ACCOUNTS_ERROR_NO_ACCOUNT \ ONLINE_ACCOUNTS_ERROR_PREFIX "NoAccount" #define ONLINE_ACCOUNTS_ERROR_USER_CANCELED \ ONLINE_ACCOUNTS_ERROR_PREFIX "UserCanceled" #define ONLINE_ACCOUNTS_ERROR_PERMISSION_DENIED \ ONLINE_ACCOUNTS_ERROR_PREFIX "PermissionDenied" #define ONLINE_ACCOUNTS_ERROR_INTERACTION_REQUIRED \ ONLINE_ACCOUNTS_ERROR_PREFIX "InteractionRequired" /* Keys for the authentication data dictionaries */ #define ONLINE_ACCOUNTS_AUTH_KEY_CLIENT_ID "ClientId" #define ONLINE_ACCOUNTS_AUTH_KEY_CLIENT_SECRET "ClientSecret" #define ONLINE_ACCOUNTS_AUTH_KEY_SCOPES "Scopes" #define ONLINE_ACCOUNTS_AUTH_KEY_ACCESS_TOKEN "AccessToken" #define ONLINE_ACCOUNTS_AUTH_KEY_EXPIRES_IN "ExpiresIn" #define ONLINE_ACCOUNTS_AUTH_KEY_GRANTED_SCOPES "GrantedScopes" #define ONLINE_ACCOUNTS_AUTH_KEY_CONSUMER_KEY "ConsumerKey" #define ONLINE_ACCOUNTS_AUTH_KEY_CONSUMER_SECRET "ConsumerSecret" #define ONLINE_ACCOUNTS_AUTH_KEY_TOKEN "Token" #define ONLINE_ACCOUNTS_AUTH_KEY_TOKEN_SECRET "TokenSecret" #define ONLINE_ACCOUNTS_AUTH_KEY_SIGNATURE_METHOD "SignatureMethod" #define ONLINE_ACCOUNTS_AUTH_KEY_SERVICE "Service" #define ONLINE_ACCOUNTS_AUTH_KEY_MECHANISMS "MechList" #define ONLINE_ACCOUNTS_AUTH_KEY_FQDN "Fqdn" #define ONLINE_ACCOUNTS_AUTH_KEY_LOCAL_IP "IpLocal" #define ONLINE_ACCOUNTS_AUTH_KEY_REMOTE_IP "IpRemote" #define ONLINE_ACCOUNTS_AUTH_KEY_CHALLENGE "Challenge" #define ONLINE_ACCOUNTS_AUTH_KEY_CHOSEN_MECHANISM "ChosenMechanism" #define ONLINE_ACCOUNTS_AUTH_KEY_RESPONSE "Response" #define ONLINE_ACCOUNTS_AUTH_KEY_STATE "state" # define ONLINE_ACCOUNTS_AUTH_SASL_STATE_FINISHED 0 # define ONLINE_ACCOUNTS_AUTH_SASL_STATE_CONTINUE 1 #define ONLINE_ACCOUNTS_AUTH_KEY_USERNAME "Username" #define ONLINE_ACCOUNTS_AUTH_KEY_PASSWORD "Password" #endif // ONLINE_ACCOUNTS_DBUS_CONSTANTS_P_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/manager_adaptor.h0000644000015600001650000001065212657306726030504 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DAEMON_MANAGER_ADAPTOR_H #define ONLINE_ACCOUNTS_DAEMON_MANAGER_ADAPTOR_H #include #include #include #include #include #include #include #include "account_info.h" #include "manager.h" namespace OnlineAccountsDaemon { class CallContext { public: explicit CallContext(QDBusContext *dbusContext); CallContext(const CallContext &other); virtual ~CallContext(); void setDelayedReply(bool delayed); void sendReply(const QList &args) const; void sendError(const QString &name, const QString &message) const; QString securityContext() const; pid_t clientPid() const; QString clientName() const; private: QDBusConnection m_connection; QDBusMessage m_message; }; class CallContextCounter: public QObject { Q_OBJECT public: static CallContextCounter *instance(); int activeContexts() const { return m_contexts; } Q_SIGNALS: void activeContextsChanged(); protected: void addContext(const CallContext &context); void removeContext(const CallContext &context); private: friend class CallContext; CallContextCounter(); int m_contexts; }; class ManagerAdaptorPrivate; class ManagerAdaptor: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "com.ubuntu.OnlineAccounts.Manager") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") public: explicit ManagerAdaptor(Manager *parent); ~ManagerAdaptor(); inline Manager *parent() const { return static_cast(QObject::parent()); } inline QDBusContext *dbusContext() const { return static_cast(parent()); } void notifyAccountChange(const AccountInfo &info, uint changeType); public Q_SLOTS: QVariantMap Authenticate(uint accountId, const QString &serviceId, bool interactive, bool invalidate, const QVariantMap ¶meters); QList GetAccounts(const QVariantMap &filters); AccountInfo RequestAccess(const QString &serviceId, const QVariantMap ¶meters, QVariantMap &credentials); Q_SIGNALS: void AccountChanged(const QString &serviceId, AccountInfo account); private: Q_DECLARE_PRIVATE(ManagerAdaptor) ManagerAdaptorPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_DAEMON_MANAGER_ADAPTOR_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/authentication_request.h0000644000015600001650000000321712657306726032146 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DAEMON_AUTHENTICATION_REQUEST_H #define ONLINE_ACCOUNTS_DAEMON_AUTHENTICATION_REQUEST_H #include #include #include #include "async_operation.h" namespace Accounts { class AuthData; } namespace OnlineAccountsDaemon { class AuthenticationRequestPrivate; class AuthenticationRequest: public AsyncOperation { Q_OBJECT public: explicit AuthenticationRequest(const CallContext &context, QObject *parent = 0); ~AuthenticationRequest(); void setInteractive(bool interactive); void invalidateCache(); void authenticate(const Accounts::AuthData &authData, const QVariantMap ¶meters); private: Q_DECLARE_PRIVATE(AuthenticationRequest) AuthenticationRequestPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_DAEMON_AUTHENTICATION_REQUEST_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/Manager0000644000015600001650000000002512657306726026475 0ustar pbuserpbgroup00000000000000#include "manager.h" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/client_registry.h0000644000015600001650000000345712657306726030573 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DAEMON_CLIENT_REGISTRY_H #define ONLINE_ACCOUNTS_DAEMON_CLIENT_REGISTRY_H #include #include #include class QDBusConnection; class QDBusMessage; namespace OnlineAccountsDaemon { class ClientRegistryPrivate; class ClientRegistry: public QObject { Q_OBJECT public: ~ClientRegistry(); static ClientRegistry *instance(); QString registerClient(const QDBusConnection &connection, const QDBusMessage &message); void registerClient(const QString &client); void registerActiveClients(const QStringList &clients); QStringList clients() const; bool hasClients() const { return !clients().isEmpty(); } QString clientSecurityContext(const QString &client) const; pid_t clientPid(const QString &client) const; Q_SIGNALS: void hasClientsChanged(); private: ClientRegistry(); Q_DECLARE_PRIVATE(ClientRegistry) ClientRegistryPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_DAEMON_CLIENT_REGISTRY_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/global.h0000644000015600001650000000205112657306726026612 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DAEMON_GLOBAL_H #define ONLINE_ACCOUNTS_DAEMON_GLOBAL_H #include #if defined(BUILDING_ONLINE_ACCOUNTS_DAEMON) # define OAD_EXPORT Q_DECL_EXPORT #else # define OAD_EXPORT Q_DECL_IMPORT #endif #endif // ONLINE_ACCOUNTS_DAEMON_GLOBAL_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/state_saver.h0000644000015600001650000000273212657306726027700 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DAEMON_STATE_SAVER_H #define ONLINE_ACCOUNTS_DAEMON_STATE_SAVER_H #include #include #include "account_info.h" namespace OnlineAccountsDaemon { typedef QPair Client; class StateSaverPrivate; class StateSaver: public QObject { Q_OBJECT public: explicit StateSaver(QObject *parent = 0); ~StateSaver(); void setAccounts(const QList &accounts); QList accounts() const; void setClients(const QList &clients); QList clients() const; private: Q_DECLARE_PRIVATE(StateSaver) StateSaverPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_DAEMON_STATE_SAVER_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/OnlineAccountsDaemon.pc.in0000644000015600001650000000047012657306726032205 0ustar pbuserpbgroup00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} libdir=${prefix}/@LIBDIR@ includedir=${prefix}/include Name: @ACCOUNTD_LIB@ Description: Binding development files for the Online Accounts simplified API Version: @PROJECT_VERSION@ Requires: Qt5Core Libs: -L${libdir} -l@ACCOUNTD_LIB@ Cflags: -I${includedir}/ online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/async_operation.h0000644000015600001650000000302412657306726030550 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DAEMON_ASYNC_OPERATION_H #define ONLINE_ACCOUNTS_DAEMON_ASYNC_OPERATION_H #include #include #include #include namespace OnlineAccountsDaemon { class CallContext; class AsyncOperationPrivate; class AsyncOperation: public QObject { Q_OBJECT public: explicit AsyncOperation(const CallContext &context, QObject *parent = 0); ~AsyncOperation(); const CallContext &context() const; protected: void setReply(const QList &reply); void setError(const QString &name, const QString &message); private: Q_DECLARE_PRIVATE(AsyncOperation) AsyncOperationPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_DAEMON_ASYNC_OPERATION_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/state_saver.cpp0000644000015600001650000001163612657306726030236 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "state_saver.h" #include #include #include #include #include #include #include #include using namespace OnlineAccountsDaemon; namespace OnlineAccountsDaemon { class StateSaverPrivate { public: StateSaverPrivate(); ~StateSaverPrivate(); static QList accountsFromJson(const QJsonValue &value); static QJsonValue accountsToJson(const QList &accounts); static QList clientsFromJson(const QJsonValue &value); static QJsonValue clientsToJson(const QList &clients); void load(); void save(); private: friend class StateSaver; QString m_cacheFile; QList m_clients; QList m_accounts; }; } // namespace StateSaverPrivate::StateSaverPrivate() { QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); if (!cacheDir.exists()) { cacheDir.mkpath("."); } m_cacheFile = cacheDir.filePath("client_account_refs.json"); load(); } StateSaverPrivate::~StateSaverPrivate() { save(); } QList StateSaverPrivate::accountsFromJson(const QJsonValue &value) { QList accounts; QJsonArray jsonAccounts = value.toArray(); Q_FOREACH(const QJsonValue &jsonAccount, jsonAccounts) { QJsonObject jsonObject = jsonAccount.toObject(); int accountId = jsonObject.value("accountId").toInt(); QVariantMap details = jsonObject.value("details").toObject().toVariantMap(); accounts.append(AccountInfo(uint(accountId), details)); } return accounts; } QJsonValue StateSaverPrivate::accountsToJson(const QList &accounts) { Q_UNUSED(accounts); return QJsonValue(); // TODO } QList StateSaverPrivate::clientsFromJson(const QJsonValue &value) { QList clients; Q_FOREACH(const QJsonValue &jsonClient, value.toArray()) { QJsonObject jsonObject = jsonClient.toObject(); QString busName = jsonObject.value("busName").toString(); QString applicationId = jsonObject.value("applicationId").toString(); clients.append(Client(busName, applicationId)); } return clients; } QJsonValue StateSaverPrivate::clientsToJson(const QList &clients) { QJsonArray clientArray; Q_FOREACH(const Client &client, clients) { QJsonObject clientObject; clientObject.insert("busName", client.first); clientObject.insert("applicationId", client.second); clientArray.append(clientObject); } return QJsonValue(clientArray); } void StateSaverPrivate::save() { QFile file(m_cacheFile); if (Q_UNLIKELY(!file.open(QIODevice::WriteOnly | QIODevice::Text))) { qWarning() << "Couldn't save state to" << m_cacheFile; return; } QJsonObject jsonObject; jsonObject.insert("accounts", accountsToJson(m_accounts)); jsonObject.insert("clients", clientsToJson(m_clients)); QJsonDocument doc(jsonObject); file.write(doc.toJson()); } void StateSaverPrivate::load() { QFile file(m_cacheFile); if (Q_UNLIKELY(!file.open(QIODevice::ReadOnly | QIODevice::Text))) { qWarning() << "Cannot open file" << m_cacheFile; return; } QByteArray contents = file.readAll(); QJsonDocument doc = QJsonDocument::fromJson(contents); if (doc.isEmpty() || !doc.isObject()) return; QJsonObject jsonObject = doc.object(); m_accounts = accountsFromJson(jsonObject.value("accounts")); m_clients = clientsFromJson(jsonObject.value("clients")); } StateSaver::StateSaver(QObject *parent): QObject(parent), d_ptr(new StateSaverPrivate) { } StateSaver::~StateSaver() { delete d_ptr; } void StateSaver::setAccounts(const QList &accounts) { Q_D(StateSaver); d->m_accounts = accounts; } QList StateSaver::accounts() const { Q_D(const StateSaver); return d->m_accounts; } void StateSaver::setClients(const QList &clients) { Q_D(StateSaver); d->m_clients = clients; } QList StateSaver::clients() const { Q_D(const StateSaver); return d->m_clients; } online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/authenticator.cpp0000644000015600001650000001517612657306732030570 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "authenticator.h" #include #include #include #include #include #include "dbus_constants.h" using namespace OnlineAccountsDaemon; namespace { QVariantMap mergeMaps(const QVariantMap &map1, const QVariantMap &map2) { if (map1.isEmpty()) return map2; if (map2.isEmpty()) return map1; QVariantMap map = map1; //map2 values will overwrite map1 values for the same keys. QMapIterator it(map2); while (it.hasNext()) { it.next(); map.insert(it.key(), it.value()); } return map; } } // namespace namespace OnlineAccountsDaemon { class AuthenticatorPrivate: public QObject { Q_OBJECT Q_DECLARE_PUBLIC(Authenticator) public: AuthenticatorPrivate(Authenticator *q); void authenticate(const Accounts::AuthData &authData, const QVariantMap ¶meters); static QString signonErrorName(int type); private Q_SLOTS: void onAuthSessionResponse(const SignOn::SessionData &sessionData); void onAuthSessionError(const SignOn::Error &error); private: SignOn::AuthSession *m_authSession; SignOn::Identity *m_identity; QVariantMap m_parameters; QVariantMap m_reply; QVariantMap m_extraReplyData; QString m_errorName; QString m_errorMessage; bool m_invalidateCache; Authenticator *q_ptr; }; } // namespace AuthenticatorPrivate::AuthenticatorPrivate(Authenticator *q): QObject(q), m_authSession(0), m_identity(0), m_invalidateCache(false), q_ptr(q) { } void AuthenticatorPrivate::authenticate(const Accounts::AuthData &authData, const QVariantMap ¶meters) { if (!m_identity) { m_identity = SignOn::Identity::existingIdentity(authData.credentialsId(), this); } if (!m_authSession) { m_authSession = m_identity->createSession(authData.method()); QObject::connect(m_authSession, SIGNAL(response(const SignOn::SessionData&)), this, SLOT(onAuthSessionResponse(const SignOn::SessionData&))); QObject::connect(m_authSession, SIGNAL(error(const SignOn::Error&)), this, SLOT(onAuthSessionError(const SignOn::Error&))); } QVariantMap allSessionData = mergeMaps(authData.parameters(), mergeMaps(parameters, m_parameters)); QString mechanism = authData.mechanism(); if (m_invalidateCache) { /* This works for OAuth 1.0 and 2.0; other authentication plugins should * implement a similar flag. */ allSessionData["ForceTokenRefresh"] = true; if (authData.method() == "password" || authData.method() == "sasl") { uint uiPolicy = allSessionData.value("UiPolicy").toUInt(); if (uiPolicy != SignOn::NoUserInteractionPolicy) { allSessionData["UiPolicy"] = SignOn::RequestPasswordPolicy; } } } m_extraReplyData.clear(); if (mechanism == "HMAC-SHA1" || mechanism == "PLAINTEXT") { /* For OAuth 1.0, let's return also the Consumer key and secret along * with the reply. */ m_extraReplyData[ONLINE_ACCOUNTS_AUTH_KEY_CONSUMER_KEY] = allSessionData.value("ConsumerKey"); m_extraReplyData[ONLINE_ACCOUNTS_AUTH_KEY_CONSUMER_SECRET] = allSessionData.value("ConsumerSecret"); } m_authSession->process(allSessionData, mechanism); } void AuthenticatorPrivate::onAuthSessionResponse(const SignOn::SessionData &sessionData) { Q_Q(Authenticator); m_reply = mergeMaps(m_extraReplyData, sessionData.toMap()); Q_EMIT q->finished(); } QString AuthenticatorPrivate::signonErrorName(int type) { #define HANDLE_CASE(name) \ case SignOn::Error::name: return ONLINE_ACCOUNTS_ERROR_PREFIX #name switch (type) { HANDLE_CASE(MechanismNotAvailable); HANDLE_CASE(MissingData); HANDLE_CASE(InvalidCredentials); HANDLE_CASE(NotAuthorized); HANDLE_CASE(WrongState); HANDLE_CASE(OperationNotSupported); HANDLE_CASE(NoConnection); HANDLE_CASE(Network); HANDLE_CASE(Ssl); HANDLE_CASE(Runtime); HANDLE_CASE(SessionCanceled); HANDLE_CASE(TimedOut); HANDLE_CASE(OperationFailed); HANDLE_CASE(TOSNotAccepted); HANDLE_CASE(ForgotPassword); HANDLE_CASE(MethodOrMechanismNotAllowed); HANDLE_CASE(IncorrectDate); case SignOn::Error::UserInteraction: return ONLINE_ACCOUNTS_ERROR_INTERACTION_REQUIRED; default: qWarning() << "Unhandled signond error code:" << type; return ONLINE_ACCOUNTS_ERROR_PREFIX "UnknownError"; }; } void AuthenticatorPrivate::onAuthSessionError(const SignOn::Error &error) { Q_Q(Authenticator); m_errorName = signonErrorName(error.type()); m_errorMessage = error.message(); Q_EMIT q->finished(); } Authenticator::Authenticator(QObject *parent): QObject(parent), d_ptr(new AuthenticatorPrivate(this)) { } Authenticator::~Authenticator() { delete d_ptr; } void Authenticator::setInteractive(bool interactive) { Q_D(Authenticator); d->m_parameters["UiPolicy"] = interactive ? SignOn::DefaultPolicy : SignOn::NoUserInteractionPolicy; } void Authenticator::invalidateCache() { Q_D(Authenticator); d->m_invalidateCache = true; } void Authenticator::authenticate(const Accounts::AuthData &authData, const QVariantMap ¶meters) { Q_D(Authenticator); d->authenticate(authData, parameters); } QVariantMap Authenticator::reply() const { Q_D(const Authenticator); return d->m_reply; } QString Authenticator::errorName() const { Q_D(const Authenticator); return d->m_errorName; } QString Authenticator::errorMessage() const { Q_D(const Authenticator); return d->m_errorMessage; } #include "authenticator.moc" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/account_info.h0000644000015600001650000000324312657306726030025 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DAEMON_ACCOUNT_INFO_H #define ONLINE_ACCOUNTS_DAEMON_ACCOUNT_INFO_H #include #include "dbus_constants.h" class QDBusArgument; namespace OnlineAccountsDaemon { struct AccountInfo { uint accountId; QVariantMap details; AccountInfo(): accountId(0) {} AccountInfo(uint accountId, const QVariantMap &details): accountId(accountId), details(details) {} QString serviceId() const { return details[ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID].toString(); } }; } // namespace QDBusArgument &operator<<(QDBusArgument &argument, const OnlineAccountsDaemon::AccountInfo &info); const QDBusArgument &operator>>(const QDBusArgument &argument, OnlineAccountsDaemon::AccountInfo &info); Q_DECLARE_METATYPE(OnlineAccountsDaemon::AccountInfo) #endif // ONLINE_ACCOUNTS_DAEMON_ACCOUNT_INFO_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/async_operation.cpp0000644000015600001650000000376512657306726031117 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "async_operation.h" #include #include "manager_adaptor.h" using namespace OnlineAccountsDaemon; namespace OnlineAccountsDaemon { class AsyncOperationPrivate { Q_DECLARE_PUBLIC(AsyncOperation) public: AsyncOperationPrivate(AsyncOperation *q, const CallContext &context); private: CallContext m_context; AsyncOperation *q_ptr; }; } // namespace AsyncOperationPrivate::AsyncOperationPrivate(AsyncOperation *q, const CallContext &context): m_context(context), q_ptr(q) { m_context.setDelayedReply(true); } AsyncOperation::AsyncOperation(const CallContext &context, QObject *parent): QObject(parent), d_ptr(new AsyncOperationPrivate(this, context)) { } AsyncOperation::~AsyncOperation() { delete d_ptr; } const CallContext &AsyncOperation::context() const { Q_D(const AsyncOperation); return d->m_context; } void AsyncOperation::setReply(const QList &reply) { Q_D(AsyncOperation); d->m_context.sendReply(reply); this->deleteLater(); } void AsyncOperation::setError(const QString &name, const QString &message) { Q_D(AsyncOperation); d->m_context.sendError(name, message); this->deleteLater(); } online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/CMakeLists.txt0000644000015600001650000000274712657306726027755 0ustar pbuserpbgroup00000000000000project(OnlineAccountsDaemon) pkg_check_modules(ACCOUNTSQT accounts-qt5 REQUIRED) pkg_check_modules(OACLIENT OnlineAccountsClient REQUIRED) pkg_check_modules(SIGNONQT libsignon-qt5 REQUIRED) set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(ACCOUNTD_LIB OnlineAccountsDaemon) include_directories(. ${CMAKE_CURRENT_BINARY_DIR}) add_definitions( ${ACCOUNTSQT_CFLAGS} ${APPARMOR_CFLAGS} ${OACLIENT_CFLAGS} ${SIGNONQT_CFLAGS} ) add_library(${ACCOUNTD_LIB} SHARED access_request.cpp async_operation.cpp authentication_request.cpp authenticator.cpp client_registry.cpp manager.cpp manager_adaptor.cpp state_saver.cpp ) #set_target_properties(${ACCOUNTD_LIB} PROPERTIES # VERSION 1.0.0 # SOVERSION 1 #) qt5_use_modules(${ACCOUNTD_LIB} DBus) target_link_libraries(${ACCOUNTD_LIB} ${ACCOUNTSQT_LDFLAGS} ${APPARMOR_LDFLAGS} ${OACLIENT_LDFLAGS} ${SIGNONQT_LDFLAGS} ) set_target_properties(${ACCOUNTD_LIB} PROPERTIES AUTOMOC TRUE) # Install install(TARGETS ${ACCOUNTD_LIB} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) # Development files configure_file(${ACCOUNTD_LIB}.pc.in ${ACCOUNTD_LIB}.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${ACCOUNTD_LIB}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(FILES "com.ubuntu.OnlineAccounts.Manager.xml" DESTINATION ${CMAKE_INSTALL_DATADIR}/dbus-1/interfaces ) install(FILES "dbus_constants.h" DESTINATION include/${ACCOUNTD_LIB}) online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/manager.cpp0000644000015600001650000005133212657306732027322 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015-2016 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "manager.h" #include #include #include #include #include #include #include #include #include #include #include #include "access_request.h" #include "authentication_request.h" #include "client_registry.h" #include "dbus_constants.h" #include "manager_adaptor.h" #include "state_saver.h" using namespace OnlineAccountsDaemon; namespace OnlineAccountsDaemon { struct ActiveAccount { ActiveAccount(): accountService(0) {} bool isValid() const { return accountService != 0; } Accounts::AccountService *accountService; QSet clients; }; typedef QPair AccountCoordinates; typedef QHash ClientMap; class ManagerPrivate: public QObject { Q_OBJECT Q_DECLARE_PUBLIC(Manager) public: ManagerPrivate(Manager *q); ~ManagerPrivate(); QString applicationIdFromServiceId(const QString &serviceId); void watchAccount(Accounts::Account *account); void handleNewAccountService(Accounts::Account *account, const Accounts::Service &service); void loadActiveAccounts(); void saveState(); ActiveAccount &addActiveAccount(Accounts::AccountId accountId, const QString &serviceName, const QString &client); ActiveAccount &addActiveAccount(Accounts::AccountId accountId, const QString &serviceName, const QStringList &clients); int authMethod(const Accounts::AuthData &authData); AccountInfo readAccountInfo(const Accounts::AccountService *as); QList getAccounts(const QVariantMap &filters, const CallContext &context); void authenticate(uint accountId, const QString &serviceId, bool interactive, bool invalidate, const QVariantMap ¶meters, const CallContext &context); void requestAccess(const QString &serviceId, const QVariantMap ¶meters, const CallContext &context); bool canAccess(const QString &context, const QString &serviceId); void notifyAccountChange(const ActiveAccount &account, uint change); private Q_SLOTS: void onActiveContextsChanged(); void onAccountServiceEnabled(bool enabled); void onAccountServiceChanged(); void onAccountEnabled(const QString &serviceId, bool enabled); void onAccountCreated(Accounts::AccountId accountId); void onLoadRequest(uint accountId, const QString &serviceId); private: ManagerAdaptor *m_adaptor; Accounts::Manager m_manager; StateSaver m_stateSaver; bool m_mustEmitNotifications; QHash m_activeAccounts; ClientMap m_clients; QList m_watchedAccounts; bool m_isIdle; Manager *q_ptr; }; } // namespace ManagerPrivate::ManagerPrivate(Manager *q): QObject(q), m_adaptor(new ManagerAdaptor(q)), m_mustEmitNotifications(false), m_isIdle(true), q_ptr(q) { CallContextCounter *counter = CallContextCounter::instance(); QObject::connect(counter, SIGNAL(activeContextsChanged()), this, SLOT(onActiveContextsChanged())); loadActiveAccounts(); QObject::connect(&m_manager, SIGNAL(accountCreated(Accounts::AccountId)), this, SLOT(onAccountCreated(Accounts::AccountId))); } ManagerPrivate::~ManagerPrivate() { saveState(); } void ManagerPrivate::onActiveContextsChanged() { Q_Q(Manager); CallContextCounter *counter = CallContextCounter::instance(); if (counter->activeContexts() == 0) { m_isIdle = true; Q_EMIT q->isIdleChanged(); } else if (m_isIdle) { m_isIdle = false; Q_EMIT q->isIdleChanged(); } } QString ManagerPrivate::applicationIdFromServiceId(const QString &serviceId) { Accounts::Service service = m_manager.service(serviceId); Accounts::ApplicationList apps = m_manager.applicationList(service); if (apps.isEmpty()) return QString(); /* TODO: to figure out the correct app, take the security context into * account */ return apps.first().name(); } void ManagerPrivate::watchAccount(Accounts::Account *account) { if (m_watchedAccounts.contains(account)) return; QObject::connect(account, SIGNAL(enabledChanged(const QString &, bool)), this, SLOT(onAccountEnabled(const QString &, bool))); m_watchedAccounts.append(account); } void ManagerPrivate::handleNewAccountService(Accounts::Account *account, const Accounts::Service &service) { AccountCoordinates coords(account->id(), service.name()); if (m_activeAccounts.contains(coords)) { /* This event is also received via the AccountService instance; we'll * handle it from there. */ return; } QStringList interestedClients; for (auto i = m_clients.constBegin(); i != m_clients.constEnd(); i++) { const Accounts::Application &application = i.value(); if (!application.serviceUsage(service).isEmpty()) { interestedClients.append(i.key()); } } ActiveAccount &activeAccount = addActiveAccount(account->id(), service.name(), interestedClients); notifyAccountChange(activeAccount, ONLINE_ACCOUNTS_INFO_CHANGE_ENABLED); } void ManagerPrivate::loadActiveAccounts() { QSet oldClients = m_stateSaver.clients().toSet(); ClientRegistry *clientRegistry = ClientRegistry::instance(); QStringList oldClientNames; Q_FOREACH(const Client &client, oldClients) { oldClientNames.append(client.first); } clientRegistry->registerActiveClients(oldClientNames); /* Build the table of the active clients */ QStringList activeClientNames = clientRegistry->clients(); Q_FOREACH(const Client &client, oldClients) { if (activeClientNames.contains(client.first)) { m_clients[client.first] = m_manager.application(client.second); } } QList oldAccounts = m_stateSaver.accounts(); Q_FOREACH(const AccountInfo &accountInfo, oldAccounts) { // If no clients are interested in this account, ignore it Accounts::Service service = m_manager.service(accountInfo.serviceId()); if (Q_UNLIKELY(!service.isValid())) continue; QStringList clients; for (auto i = m_clients.constBegin(); i != m_clients.constEnd(); i++) { const Accounts::Application &application = i.value(); if (!application.serviceUsage(service).isEmpty()) { clients.append(i.key()); } } if (clients.isEmpty()) { // no one is interested in this account continue; } ActiveAccount &activeAccount = addActiveAccount(accountInfo.accountId, service.name(), clients); if (Q_UNLIKELY(!activeAccount.isValid())) continue; if (!activeAccount.accountService->isEnabled()) { // the account got disabled while this daemon was not running notifyAccountChange(activeAccount, ONLINE_ACCOUNTS_INFO_CHANGE_DISABLED); } else { AccountInfo newAccountInfo = readAccountInfo(activeAccount.accountService); if (newAccountInfo.details != accountInfo.details) { notifyAccountChange(activeAccount, ONLINE_ACCOUNTS_INFO_CHANGE_UPDATED); } } } /* Last, go through all active clients and see if there are new accounts * for any of them. */ Q_FOREACH(Accounts::AccountId accountId, m_manager.accountListEnabled()) { Accounts::Account *account = m_manager.account(accountId); if (Q_UNLIKELY(!account)) continue; watchAccount(account); Q_FOREACH(Accounts::Service service, account->enabledServices()) { handleNewAccountService(account, service); } } } void ManagerPrivate::saveState() { QList clients; for (auto i = m_clients.constBegin(); i != m_clients.constEnd(); i++) { const Accounts::Application &application = i.value(); clients.append(Client(i.key(), application.name())); } m_stateSaver.setClients(clients); QList accounts; Q_FOREACH(const ActiveAccount &activeAccount, m_activeAccounts) { if (!activeAccount.isValid()) continue; accounts.append(readAccountInfo(activeAccount.accountService)); } m_stateSaver.setAccounts(accounts); } void ManagerPrivate::notifyAccountChange(const ActiveAccount &account, uint change) { AccountInfo info = readAccountInfo(account.accountService); m_adaptor->notifyAccountChange(info, change); } ActiveAccount &ManagerPrivate::addActiveAccount(Accounts::AccountId accountId, const QString &serviceName, const QString &client) { return addActiveAccount(accountId, serviceName, QStringList() << client); } ActiveAccount &ManagerPrivate::addActiveAccount(Accounts::AccountId accountId, const QString &serviceName, const QStringList &clients) { ActiveAccount &activeAccount = m_activeAccounts[AccountCoordinates(accountId, serviceName)]; activeAccount.clients += clients.toSet(); if (!activeAccount.accountService) { Accounts::Account *account = m_manager.account(accountId); if (Q_UNLIKELY(!account)) return activeAccount; Accounts::Service service = m_manager.service(serviceName); auto as = new Accounts::AccountService(account, service); activeAccount.accountService = as; QObject::connect(as, SIGNAL(enabled(bool)), this, SLOT(onAccountServiceEnabled(bool))); QObject::connect(as, SIGNAL(changed()), this, SLOT(onAccountServiceChanged())); } return activeAccount; } int ManagerPrivate::authMethod(const Accounts::AuthData &authData) { QString method = authData.method(); QString mechanism = authData.mechanism(); if (method == "oauth2") { if (mechanism == "web_server" || mechanism == "user_agent") { return ONLINE_ACCOUNTS_AUTH_METHOD_OAUTH2; } else if (mechanism == "HMAC-SHA1" || mechanism == "PLAINTEXT") { return ONLINE_ACCOUNTS_AUTH_METHOD_OAUTH1; } } else if (method == "sasl") { return ONLINE_ACCOUNTS_AUTH_METHOD_SASL; } else if (method == "password") { return ONLINE_ACCOUNTS_AUTH_METHOD_PASSWORD; } return ONLINE_ACCOUNTS_AUTH_METHOD_UNKNOWN; } AccountInfo ManagerPrivate::readAccountInfo(const Accounts::AccountService *as) { QVariantMap info; info[ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME] = as->account()->displayName(); info[ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID] = as->service().name(); info[ONLINE_ACCOUNTS_INFO_KEY_AUTH_METHOD] = authMethod(as->authData()); QString settingsPrefix(QStringLiteral(ONLINE_ACCOUNTS_INFO_KEY_SETTINGS)); /* First, read the global settings */ Accounts::Account *a = as->account(); a->selectService(); Q_FOREACH(const QString &key, a->allKeys()) { if (key == "enabled" || key == "CredentialsId" || key == "name" || key.startsWith("auth/")) continue; info[settingsPrefix + key] = a->value(key); } /* Then, add service-specific settings */ Q_FOREACH(const QString &key, as->allKeys()) { if (key == "enabled") continue; info[settingsPrefix + key] = as->value(key); } return AccountInfo(as->account()->id(), info); } QList ManagerPrivate::getAccounts(const QVariantMap &filters, const CallContext &context) { QString desiredApplicationId = filters.value("applicationId").toString(); QString desiredServiceId = filters.value("serviceId").toString(); Accounts::AccountId desiredAccountId = filters.value("accountId").toUInt(); Accounts::Application application = desiredApplicationId.isEmpty() ? Accounts::Application() : m_manager.application(desiredApplicationId); if (application.isValid() && canAccess(context.securityContext(), desiredApplicationId)) { m_clients.insert(context.clientName(), application); } QList accounts; Q_FOREACH(Accounts::AccountId accountId, m_manager.accountListEnabled()) { if (desiredAccountId != 0 && accountId != desiredAccountId) { continue; } Accounts::Account *account = m_manager.account(accountId); if (Q_UNLIKELY(!account)) continue; Q_FOREACH(Accounts::Service service, account->enabledServices()) { if (!desiredServiceId.isEmpty() && service.name() != desiredServiceId) { continue; } if (!canAccess(context.securityContext(), service.name())) { continue; } if (application.isValid() && application.serviceUsage(service).isEmpty()) { /* The application does not support this service */ continue; } ActiveAccount &activeAccount = addActiveAccount(accountId, service.name(), context.clientName()); accounts.append(readAccountInfo(activeAccount.accountService)); } } return accounts; } void ManagerPrivate::authenticate(uint accountId, const QString &serviceId, bool interactive, bool invalidate, const QVariantMap ¶meters, const CallContext &context) { if (!canAccess(context.securityContext(), serviceId)) { context.sendError(ONLINE_ACCOUNTS_ERROR_PERMISSION_DENIED, QString("Access to service ID %1 forbidden").arg(serviceId)); return; } ActiveAccount &activeAccount = addActiveAccount(accountId, serviceId, context.clientName()); auto as = activeAccount.accountService; if (!as || !as->isEnabled()) { context.sendError(ONLINE_ACCOUNTS_ERROR_PERMISSION_DENIED, QString("Account %1 is disabled").arg(accountId)); return; } AuthenticationRequest *authentication = new AuthenticationRequest(context, this); authentication->setInteractive(interactive); if (invalidate) { authentication->invalidateCache(); } authentication->authenticate(as->authData(), parameters); } void ManagerPrivate::requestAccess(const QString &serviceId, const QVariantMap ¶meters, const CallContext &context) { Q_UNUSED(parameters); if (!canAccess(context.securityContext(), serviceId)) { context.sendError(ONLINE_ACCOUNTS_ERROR_PERMISSION_DENIED, QString("Access to service ID %1 forbidden").arg(serviceId)); return; } AccessRequest *accessRequest = new AccessRequest(context, this); QObject::connect(accessRequest, SIGNAL(loadRequest(uint, const QString&)), this, SLOT(onLoadRequest(uint, const QString&))); QString applicationId = applicationIdFromServiceId(serviceId); accessRequest->requestAccess(applicationId, serviceId, parameters, context.clientPid()); } bool ManagerPrivate::canAccess(const QString &context, const QString &serviceId) { // Could not determine peer's AppArmor context, so deny access if (context.isEmpty()) { return false; } // Unconfined processes can access anything if (context == "unconfined") { return true; } // Try to extract the click package name from the AppArmor context. int pos = context.indexOf('_'); if (pos < 0) { qWarning() << "AppArmor context doesn't contain package ID: " << context; return false; } QString pkgname = context.left(pos); // Do the same on the service ID: we are only dealing with // confined apps at this point, so only $pkgname prefixed // services are accessible. pos = serviceId.indexOf('_'); if (pos < 0) { return false; } return serviceId.left(pos) == pkgname; } void ManagerPrivate::onAccountServiceEnabled(bool enabled) { auto as = qobject_cast(sender()); ActiveAccount &activeAccount = m_activeAccounts[AccountCoordinates(as->account()->id(), as->service().name())]; if (Q_UNLIKELY(!activeAccount.isValid())) return; notifyAccountChange(activeAccount, enabled ? ONLINE_ACCOUNTS_INFO_CHANGE_ENABLED : ONLINE_ACCOUNTS_INFO_CHANGE_DISABLED); } void ManagerPrivate::onAccountServiceChanged() { auto as = qobject_cast(sender()); if (!as->isEnabled()) { // Nobody cares about disabled accounts return; } ActiveAccount &activeAccount = m_activeAccounts[AccountCoordinates(as->account()->id(), as->service().name())]; if (Q_UNLIKELY(!activeAccount.isValid())) return; notifyAccountChange(activeAccount, ONLINE_ACCOUNTS_INFO_CHANGE_UPDATED); } void ManagerPrivate::onAccountEnabled(const QString &serviceId, bool enabled) { if (!enabled) { /* We don't care about these. If we have an AccountService active, we * will be receiving the same event though it. */ return; } auto account = qobject_cast(sender()); handleNewAccountService(account, m_manager.service(serviceId)); } void ManagerPrivate::onAccountCreated(Accounts::AccountId accountId) { Accounts::Account *account = m_manager.account(accountId); if (Q_UNLIKELY(!account)) return; watchAccount(account); Q_FOREACH(Accounts::Service service, account->enabledServices()) { handleNewAccountService(account, service); } } void ManagerPrivate::onLoadRequest(uint accountId, const QString &serviceId) { AccessRequest *request = qobject_cast(sender()); ActiveAccount &activeAccount = addActiveAccount(accountId, serviceId, request->context().clientName()); auto as = activeAccount.accountService; request->setAccountInfo(readAccountInfo(as), as->authData()); } Manager::Manager(QObject *parent): QObject(parent), d_ptr(new ManagerPrivate(this)) { } Manager::~Manager() { delete d_ptr; } bool Manager::isIdle() const { Q_D(const Manager); return d->m_isIdle; } QList Manager::getAccounts(const QVariantMap &filters, const CallContext &context) { Q_D(Manager); return d->getAccounts(filters, context); } void Manager::authenticate(uint accountId, const QString &serviceId, bool interactive, bool invalidate, const QVariantMap ¶meters, const CallContext &context) { Q_D(Manager); d->authenticate(accountId, serviceId, interactive, invalidate, parameters, context); } void Manager::requestAccess(const QString &serviceId, const QVariantMap ¶meters, const CallContext &context) { Q_D(Manager); d->requestAccess(serviceId, parameters, context); } void Manager::onDisconnected() { qDebug() << "Disconnected from D-Bus: quitting"; QCoreApplication::instance()->quit(); } void *oad_create_manager(QObject *parent) { return new Manager(parent); } #include "manager.moc" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/manager.h0000644000015600001650000000417012657306726026770 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DAEMON_MANAGER_H #define ONLINE_ACCOUNTS_DAEMON_MANAGER_H #include #include #include #include #include #include "global.h" extern "C" { OAD_EXPORT void *oad_create_manager(QObject *parent); } namespace OnlineAccountsDaemon { struct AccountInfo; class CallContext; class ManagerAdaptor; class ManagerPrivate; class Manager: public QObject, protected QDBusContext { Q_OBJECT Q_PROPERTY(bool isIdle READ isIdle NOTIFY isIdleChanged) public: explicit Manager(QObject *parent = 0); ~Manager(); bool isIdle() const; QList getAccounts(const QVariantMap &filters, const CallContext &context); void authenticate(uint accountId, const QString &serviceId, bool interactive, bool invalidate, const QVariantMap ¶meters, const CallContext &context); void requestAccess(const QString &serviceId, const QVariantMap ¶meters, const CallContext &context); public Q_SLOTS: void onDisconnected(); Q_SIGNALS: void isIdleChanged(); private: friend class ManagerAdaptor; Q_DECLARE_PRIVATE(Manager) ManagerPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_DAEMON_MANAGER_H ././@LongLink0000000000000000000000000000015200000000000011213 Lustar 00000000000000online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/com.ubuntu.OnlineAccounts.Manager.xmlonline-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/com.ubuntu.OnlineAccounts.Manage0000644000015600001650000001536512657306726033351 0ustar pbuserpbgroup00000000000000 online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccountsDaemon/access_request.cpp0000644000015600001650000001021112657306726030713 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsDaemon * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "access_request.h" #include #include #include #include #include "account_info.h" #include "authenticator.h" using namespace OnlineAccountsDaemon; namespace OnlineAccountsDaemon { class AccessRequestPrivate: public QObject { Q_OBJECT Q_DECLARE_PUBLIC(AccessRequest) public: AccessRequestPrivate(AccessRequest *q); void requestAccess(const QString &applicationId, const QString &serviceId, const QVariantMap ¶meters, pid_t clientPid); private Q_SLOTS: void onSetupFinished(QVariantMap reply); void onAuthenticationFinished(); private: OnlineAccountsClient::Setup m_setup; Authenticator m_authenticator; QVariantMap m_parameters; AccountInfo m_accountInfo; AccessRequest *q_ptr; }; } // namespace AccessRequestPrivate::AccessRequestPrivate(AccessRequest *q): QObject(q), q_ptr(q) { QObject::connect(&m_setup, SIGNAL(finished(QVariantMap)), this, SLOT(onSetupFinished(QVariantMap))); QObject::connect(&m_authenticator, SIGNAL(finished()), this, SLOT(onAuthenticationFinished())); } void AccessRequestPrivate::requestAccess(const QString &applicationId, const QString &serviceId, const QVariantMap ¶meters, pid_t clientPid) { m_parameters = parameters; m_setup.setApplicationId(applicationId); m_setup.setServiceId(serviceId); m_setup.setClientPid(clientPid); m_setup.exec(); } void AccessRequestPrivate::onSetupFinished(QVariantMap reply) { Q_Q(AccessRequest); uint accountId = reply[QStringLiteral("accountId")].toUInt(); if (accountId == 0) { q->setError(ONLINE_ACCOUNTS_ERROR_PERMISSION_DENIED, "Authorization was not granted"); } else { Q_EMIT q->loadRequest(accountId, m_setup.serviceId()); } } void AccessRequestPrivate::onAuthenticationFinished() { Q_Q(AccessRequest); /* We don't check for authentication errors here. Even if an error * occurred, we still have to return the account info to the client. * So, if an error occurred, we'll just return empty authentication data to * the client. */ QList args; QDBusArgument infoArg; infoArg << m_accountInfo; args << QVariant::fromValue(infoArg); args << m_authenticator.reply(); q->setReply(args); } AccessRequest::AccessRequest(const CallContext &context, QObject *parent): AsyncOperation(context, parent), d_ptr(new AccessRequestPrivate(this)) { } AccessRequest::~AccessRequest() { delete d_ptr; } void AccessRequest::requestAccess(const QString &applicationId, const QString &serviceId, const QVariantMap ¶meters, pid_t clientPid) { Q_D(AccessRequest); d->requestAccess(applicationId, serviceId, parameters, clientPid); } void AccessRequest::setAccountInfo(const AccountInfo &accountInfo, const Accounts::AuthData &authData) { Q_D(AccessRequest); d->m_accountInfo = accountInfo; d->m_authenticator.authenticate(authData, d->m_parameters); } #include "access_request.moc" online-accounts-api-0.1+16.04.20160212/src/lib/Ubuntu/0000755000015600001650000000000012657307121022403 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/src/lib/Ubuntu/OnlineAccounts.2/0000755000015600001650000000000012657307121025467 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/src/lib/Ubuntu/OnlineAccounts.2/account.h0000644000015600001650000000543212657306732027307 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsModule * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_MODULE_ACCOUNT_H #define ONLINE_ACCOUNTS_MODULE_ACCOUNT_H #include #include #include namespace OnlineAccounts { class Account; } namespace OnlineAccountsModule { class AccountPrivate; class Account: public QObject { Q_OBJECT Q_ENUMS(AuthenticationMethod ErrorCode) Q_PROPERTY(bool valid READ isValid NOTIFY validChanged) Q_PROPERTY(QString displayName READ displayName NOTIFY accountChanged) Q_PROPERTY(int accountId READ accountId CONSTANT) Q_PROPERTY(QString serviceId READ serviceId CONSTANT) Q_PROPERTY(AuthenticationMethod authenticationMethod \ READ authenticationMethod CONSTANT) Q_PROPERTY(QVariantMap settings READ settings NOTIFY accountChanged) public: enum AuthenticationMethod { // Make sure these are kept in sync with those from OnlineAccountsQt AuthenticationMethodUnknown = 0, AuthenticationMethodOAuth1, AuthenticationMethodOAuth2, AuthenticationMethodPassword, AuthenticationMethodSasl, }; enum ErrorCode { // Make sure these are kept in sync with those from OnlineAccountsQt ErrorCodeNoError = 0, ErrorCodeNoAccount, ErrorCodeWrongType, ErrorCodeUserCanceled, ErrorCodePermissionDenied, ErrorCodeInteractionRequired, }; explicit Account(OnlineAccounts::Account *account, QObject *parent = 0); ~Account(); bool isValid() const; QString displayName() const; int accountId() const; QString serviceId() const; AuthenticationMethod authenticationMethod() const; QVariantMap settings() const; OnlineAccounts::Account *internalObject() const; Q_INVOKABLE void authenticate(const QVariantMap ¶ms); Q_SIGNALS: void validChanged(); void accountChanged(); void authenticationReply(const QVariantMap &authenticationData); private: Q_DECLARE_PRIVATE(Account) AccountPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_MODULE_ACCOUNT_H online-accounts-api-0.1+16.04.20160212/src/lib/Ubuntu/OnlineAccounts.2/authentication_data.cpp0000644000015600001650000000307312657306726032220 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsModule * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "authentication_data.h" #include "OnlineAccounts/PendingCall" #include QVariantMap replyToMap(const OnlineAccounts::PendingCall &call) { OnlineAccounts::AuthenticationReply reply(call); return reply.data(); } OnlineAccounts::AuthenticationData authenticationDataFromMap(const QVariantMap ¶ms, OnlineAccounts::AuthenticationMethod method) { OnlineAccounts::AuthenticationData data(method); QVariantMap cleanedParams(params); data.setInteractive(params.value("interactive", true).toBool()); if (params["invalidateCachedReply"].toBool()) { data.invalidateCachedReply(); } cleanedParams.remove("interactive"); cleanedParams.remove("invalidateCachedReply"); data.setParameters(cleanedParams); return data; } online-accounts-api-0.1+16.04.20160212/src/lib/Ubuntu/OnlineAccounts.2/plugin.h0000644000015600001650000000222612657306726027152 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsModule * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_MODULE_PLUGIN_H #define ONLINE_ACCOUNTS_MODULE_PLUGIN_H #include namespace OnlineAccountsModule { class Plugin: public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") public: void registerTypes(const char* uri); }; } // namespace #endif // ONLINE_ACCOUNTS_MODULE_PLUGIN_H online-accounts-api-0.1+16.04.20160212/src/lib/Ubuntu/OnlineAccounts.2/plugin.cpp0000644000015600001650000000205412657306726027504 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsModule * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "plugin.h" #include "account_model.h" #include #include using namespace OnlineAccountsModule; void Plugin::registerTypes(const char* uri) { qDebug() << Q_FUNC_INFO << uri; qmlRegisterType(uri, 2, 0, "AccountModel"); } online-accounts-api-0.1+16.04.20160212/src/lib/Ubuntu/OnlineAccounts.2/account_model.h0000644000015600001650000000602612657306740030466 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsModule * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_MODULE_ACCOUNT_MODEL_H #define ONLINE_ACCOUNTS_MODULE_ACCOUNT_MODEL_H #include #include #include #include namespace OnlineAccountsModule { class Account; class AccountModelPrivate; class AccountModel: public QAbstractListModel, public QQmlParserStatus { Q_OBJECT Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(int count READ rowCount NOTIFY countChanged) Q_PROPERTY(bool ready READ isReady NOTIFY isReadyChanged) Q_PROPERTY(QString applicationId READ applicationId \ WRITE setApplicationId NOTIFY applicationIdChanged) Q_PROPERTY(QString serviceId READ serviceId \ WRITE setServiceId NOTIFY serviceIdChanged) Q_PROPERTY(QList accountList READ accountList \ NOTIFY accountListChanged) public: enum Roles { DisplayNameRole = Qt::UserRole + 1, ValidRole, AccountIdRole, ServiceIdRole, AuthenticationMethodRole, SettingsRole, AccountRole, }; explicit AccountModel(QObject *parent = 0); ~AccountModel(); bool isReady() const; void setApplicationId(const QString &applicationId); QString applicationId() const; void setServiceId(const QString &serviceId); QString serviceId() const; QList accountList() const; Q_INVOKABLE void requestAccess(const QString &service, const QVariantMap ¶ms); Q_INVOKABLE QVariant get(int row, const QString &roleName) const; // reimplemented virtual methods int rowCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QHash roleNames() const; void classBegin() Q_DECL_OVERRIDE; void componentComplete() Q_DECL_OVERRIDE; Q_SIGNALS: void isReadyChanged(); void countChanged(); void applicationIdChanged(); void serviceIdChanged(); void accountListChanged(); void accessReply(const QVariantMap &reply, const QVariantMap &authenticationData); private: Q_DECLARE_PRIVATE(AccountModel) AccountModelPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_MODULE_ACCOUNT_MODEL_H online-accounts-api-0.1+16.04.20160212/src/lib/Ubuntu/OnlineAccounts.2/account.cpp0000644000015600001650000002072212657306732027641 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsModule * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "account.h" #include "authentication_data.h" #include "OnlineAccounts/Account" #include "OnlineAccounts/AuthenticationData" #include "OnlineAccounts/AuthenticationReply" #include "OnlineAccounts/PendingCall" using namespace OnlineAccountsModule; namespace OnlineAccountsModule { class AccountPrivate: public QObject { Q_OBJECT Q_DECLARE_PUBLIC(Account) public: AccountPrivate(OnlineAccounts::Account *account, Account *q); private Q_SLOTS: void onAuthenticationFinished(); private: OnlineAccounts::Account *m_account; mutable Account *q_ptr; }; } // namespace AccountPrivate::AccountPrivate(OnlineAccounts::Account *account, Account *q): m_account(account), q_ptr(q) { QObject::connect(account, SIGNAL(changed()), q, SIGNAL(accountChanged())); QObject::connect(account, SIGNAL(disabled()), q, SIGNAL(validChanged())); } void AccountPrivate::onAuthenticationFinished() { Q_Q(Account); auto watcher = qobject_cast(sender()); OnlineAccounts::AuthenticationReply reply(*watcher); QVariantMap map; if (reply.hasError()) { map["errorCode"] = reply.error().code(); map["errorText"] = reply.error().text(); } else { map = replyToMap(*watcher); } Q_EMIT q->authenticationReply(map); } /*! * \qmltype Account * \inqmlmodule Ubuntu.OnlineAccounts 2.0 * \ingroup Ubuntu * \brief Representation of an online account * * The Account object holds the information related to an account and provides * methods to interact with it. * It's not possible to create such objects from QML; instead, they are * returned by the \l AccountModel in the \c account role or in the \l * {AccountModel::accountList} { \c accountList} property. * * Here's an example on how to use the account object in a delegate: * * \qml * import QtQuick 2.0 * import Ubuntu.OnlineAccounts 2.0 * * ListView { * model: AccountModel {} * delegate: Button { * text: "Authenticate " + model.displayName * onClicked: model.account.authenticate({}) * Connections { * target: model.account * onAuthenticationReply: { * console.log("Access token is " + reply['AccessToken']) * } * } * } * } * \endqml * * \target errorCode * \section3 Error codes used in this module * Some operations, such as the \l Account::authenticate() and the \l * AccountModel::requestAccess() methods, can fail and return one of these * error codes: * \list * \li \c Account.ErrorCodeNoAccount - The accounts is invalid * \li \c Account.ErrorCodeUserCanceled - The operation was canceled by the user * \li \c Account.ErrorCodePermissionDenied - The application has no * permission to complete the operation * \endlist */ Account::Account(OnlineAccounts::Account *account, QObject *parent): QObject(parent), d_ptr(new AccountPrivate(account, this)) { } Account::~Account() { delete d_ptr; } /*! * \qmlproperty bool Account::valid * * Whether the account object is valid; this is usually \c true, because the \c * AccountModel never gives out invalid accounts. However, it can happen that a * valid account becomes invalid while the application is using it (if, for * instance, the user deleted the account or revoked the application's access * rights to use it). As soon as this property becomes \c false, the * application should stop using this account. */ bool Account::isValid() const { Q_D(const Account); return d->m_account->isValid(); } /*! * \qmlproperty string Account::displayName * * The display name of the account. This is usually the user's login name, but * applications should not rely on the value of this property. Use it only for * display purposes. */ QString Account::displayName() const { Q_D(const Account); return d->m_account->displayName(); } /*! * \qmlproperty int Account::accountId * * Numeric identifier of the account. This property remains constant during the * lifetime of the account. Note, however, that if the user deletes the account * and re-creates it, its ID will be different. */ int Account::accountId() const { Q_D(const Account); return d->m_account->id(); } /*! * \qmlproperty int Account::serviceId * * Identifier for the service used with the account. */ QString Account::serviceId() const { Q_D(const Account); return d->m_account->serviceId(); } /*! * \qmlproperty enumeration Account::authenticationMethod * * The authentication method used when authenticating with the account. * Currently, these authentication methods are supported: * \list * \li \c Account.AuthenticationMethodOAuth1 - OAuth 1.0 * \li \c Account.AuthenticationMethodOAuth2 - OAuth 2.0 * \li \c Account.AuthenticationMethodSasl - SASL * \li \c Account.AuthenticationMethodPassword - username/password * \endlist */ Account::AuthenticationMethod Account::authenticationMethod() const { Q_D(const Account); return AuthenticationMethod(d->m_account->authenticationMethod()); } /*! * \qmlproperty jsobject Account::settings * * A dictionary of the settings stored into the account. */ QVariantMap Account::settings() const { Q_D(const Account); QVariantMap ret; Q_FOREACH(const QString &key, d->m_account->keys()) { ret.insert(key, d->m_account->setting(key)); } return ret; } OnlineAccounts::Account *Account::internalObject() const { Q_D(const Account); return d->m_account; } /*! * \qmlsignal Account::authenticationReply(jsobject authenticationData) * * Emitted when the authentication completes. The \a authenticationData object * will contain the authentication reply. If the authentication failed, the * following two keys will be present: * \list * \li \c errorCode is an \l {errorCode} {error code} * \li \c errorText is a textual description of the error, not meant for the * end-user; it can be used for debugging purposes * \endlist */ /*! * \qmlmethod void Account::authenticate(jsobject params) * * Perform the authentication on this account. The \a params parameter can be * used to pass authentication data, such as the ClientId and ClientSecret used * in the OAuth flow. The list of the supported authentication parameters * depend on the authentication method being used, and are documented in the * Online Accounts development Guide in the Ubuntu Developer Portal. * * There are, however, two authentication parameters which are available * regardless of the authentication method being used: * \list * \li \c invalidateCachedReply can be set to \c true when the previous * authentication reply returned an invalid access token. It will ensure * the creation of a new access token. * \li \c interactive is \c true by default; if set to \c false, it will ensure * that no interaction with the user will occur. * \endlist * * Each call to this method will cause the \l authenticationReply signal to be * emitted at some time later. Note that the authentication might involve * interactions with the network or with the end-user, so don't expect a reply * to be emitted immediately. * * \sa authenticationReply */ void Account::authenticate(const QVariantMap ¶ms) { Q_D(Account); auto method = d->m_account->authenticationMethod(); OnlineAccounts::PendingCall call = d->m_account->authenticate(authenticationDataFromMap(params, method)); OnlineAccounts::PendingCallWatcher *watcher = new OnlineAccounts::PendingCallWatcher(call, d->m_account); QObject::connect(watcher, SIGNAL(finished()), d, SLOT(onAuthenticationFinished())); } #include "account.moc" online-accounts-api-0.1+16.04.20160212/src/lib/Ubuntu/OnlineAccounts.2/authentication_data.h0000644000015600001650000000253012657306726031662 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsModule * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_MODULE_AUTHENTICATION_DATA_H #define ONLINE_ACCOUNTS_MODULE_AUTHENTICATION_DATA_H namespace OnlineAccounts { class PendingCall; } #include "OnlineAccounts/AuthenticationData" #include QVariantMap replyToMap(const OnlineAccounts::PendingCall &call); OnlineAccounts::AuthenticationData authenticationDataFromMap(const QVariantMap ¶ms, OnlineAccounts::AuthenticationMethod method = OnlineAccounts::AuthenticationMethodUnknown); #endif // ONLINE_ACCOUNTS_MODULE_AUTHENTICATION_DATA_H online-accounts-api-0.1+16.04.20160212/src/lib/Ubuntu/OnlineAccounts.2/qmldir0000644000015600001650000000006712657306726026717 0ustar pbuserpbgroup00000000000000module Ubuntu.OnlineAccounts plugin OnlineAccountsQML online-accounts-api-0.1+16.04.20160212/src/lib/Ubuntu/OnlineAccounts.2/account_model.cpp0000644000015600001650000003472212657306740031025 0ustar pbuserpbgroup00000000000000/* * This file is part of OnlineAccountsModule * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "account_model.h" #include "account.h" #include "authentication_data.h" #include "OnlineAccounts/Account" #include "OnlineAccounts/AuthenticationData" #include "OnlineAccounts/Manager" #include "OnlineAccounts/PendingCall" #include #include #include using namespace OnlineAccountsModule; namespace OnlineAccountsModule { class AccountModelPrivate: public QObject { Q_OBJECT Q_DECLARE_PUBLIC(AccountModel) public: AccountModelPrivate(AccountModel *q); void queueUpdate(); Account *handleAccount(OnlineAccounts::Account *account); private Q_SLOTS: void update(); void updateAccountList(); void onAccountAvailable(OnlineAccounts::Account *account); void onAccessRequestFinished(); void onAccountValidChanged(); void onAccountChanged(); private: QHash roleNames; OnlineAccounts::Manager *m_manager; QList m_accounts; QString m_applicationId; QString m_serviceId; bool m_isReady; bool m_updateQueued; bool m_applicationIdChanged; bool m_serviceIdChanged; mutable AccountModel *q_ptr; }; } // namespace AccountModelPrivate::AccountModelPrivate(AccountModel *q): QObject(q), m_manager(0), m_isReady(false), m_updateQueued(true), // because componentComplete will be called m_applicationIdChanged(false), m_serviceIdChanged(false), q_ptr(q) { roleNames[AccountModel::DisplayNameRole] = "displayName"; roleNames[AccountModel::ValidRole] = "valid"; roleNames[AccountModel::AccountIdRole] = "accountId"; roleNames[AccountModel::ServiceIdRole] = "serviceId"; roleNames[AccountModel::AuthenticationMethodRole] = "authenticationMethod"; roleNames[AccountModel::SettingsRole] = "settings"; roleNames[AccountModel::AccountRole] = "account"; } void AccountModelPrivate::queueUpdate() { Q_Q(AccountModel); if (m_updateQueued) return; m_updateQueued = true; QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); if (m_isReady) { m_isReady = false; Q_EMIT q->isReadyChanged(); } } void AccountModelPrivate::updateAccountList() { Q_Q(AccountModel); m_serviceIdChanged = false; auto accountObjects = m_manager->availableAccounts(m_serviceId); q->beginResetModel(); m_accounts.clear(); Q_FOREACH(OnlineAccounts::Account *account, accountObjects) { handleAccount(account); } q->endResetModel(); Q_EMIT q->accountListChanged(); m_isReady = true; Q_EMIT q->isReadyChanged(); } Account *AccountModelPrivate::handleAccount(OnlineAccounts::Account *account) { /* First, check if the account is already handled */ Q_FOREACH(Account *a, m_accounts) { if (account == a->internalObject()) { return a; } } Account *a = new Account(account, this); QQmlEngine::setObjectOwnership(a, QQmlEngine::CppOwnership); QObject::connect(a, SIGNAL(validChanged()), this, SLOT(onAccountValidChanged())); QObject::connect(a, SIGNAL(accountChanged()), this, SLOT(onAccountChanged())); m_accounts.append(a); return a; } void AccountModelPrivate::update() { m_updateQueued = false; if (m_applicationId.isEmpty()) { QStringList parts = QString::fromUtf8(qgetenv("APP_ID")).split('_'); if (parts.count() == 3) { m_applicationId = QStringList(parts.mid(0, 2)).join('_'); m_applicationIdChanged = true; } else { qWarning() << "Ubuntu.OnlineAccounts: No APP_ID defined " "and no applicationId given!"; return; } } if (m_applicationIdChanged) { delete m_manager; m_manager = new OnlineAccounts::Manager(m_applicationId); QObject::connect(m_manager, SIGNAL(ready()), this, SLOT(updateAccountList())); QObject::connect(m_manager, SIGNAL(accountAvailable(OnlineAccounts::Account*)), this, SLOT(onAccountAvailable(OnlineAccounts::Account*))); m_applicationIdChanged = false; } if (m_serviceIdChanged && m_manager->isReady()) { updateAccountList(); } } void AccountModelPrivate::onAccountAvailable(OnlineAccounts::Account *account) { Q_Q(AccountModel); if (!m_serviceId.isEmpty() && account->serviceId() != m_serviceId) { // ignore this account return; } int index = m_accounts.count(); q->beginInsertRows(QModelIndex(), index, index); handleAccount(account); q->endInsertRows(); Q_EMIT q->accountListChanged(); } void AccountModelPrivate::onAccessRequestFinished() { Q_Q(AccountModel); auto watcher = qobject_cast(sender()); OnlineAccounts::RequestAccessReply reply(*watcher); QVariantMap accountData; QVariantMap authenticationData; if (reply.hasError()) { accountData["errorCode"] = reply.error().code(); accountData["errorText"] = reply.error().text(); } else { OnlineAccounts::Account *account = reply.account(); accountData["account"] = QVariant::fromValue(handleAccount(account)); authenticationData = replyToMap(*watcher); } Q_EMIT q->accessReply(accountData, authenticationData); } void AccountModelPrivate::onAccountValidChanged() { Q_Q(AccountModel); Account *account = qobject_cast(sender()); int i = m_accounts.indexOf(account); if (Q_UNLIKELY(i < 0)) { qWarning() << "Got signal from unhandled account!"; return; } Q_ASSERT(!account->isValid()); q->beginRemoveRows(QModelIndex(), i, i); QObject::disconnect(account, 0, this, 0); account->deleteLater(); m_accounts.removeAt(i); q->endRemoveRows(); Q_EMIT q->accountListChanged(); } void AccountModelPrivate::onAccountChanged() { Q_Q(AccountModel); Account *account = qobject_cast(sender()); int i = m_accounts.indexOf(account); if (Q_UNLIKELY(i < 0)) { qWarning() << "Got signal from unhandled account!"; return; } QModelIndex idx = q->index(i, 0); q->dataChanged(idx, idx); } /*! * \qmltype AccountModel * \inqmlmodule Ubuntu.OnlineAccounts 2.0 * \ingroup Ubuntu * \brief Model of available online accounts. * * The AccountModel lists all the accounts available to the application. * \qml * import QtQuick 2.0 * import Ubuntu.OnlineAccounts 2.0 * * ListView { * model: AccountModel { * applicationId: "myapp.developer_myapp" * } * delegate: Text { * text: model.displayName * } * } * \endqml * * The model defines the following roles: * * \list * \li \c displayName is the name of the account (usually the user's login) * \li \c accountId is a numeric ID for the account * \li \c serviceId is a service identifier (e.g., "myapp.developer_myapp_google") * \li \c authenticationMethod is the authentication method used on this * account; \sa Account::authenticationMethod * \li \c settings is a dictionary of the settings stored into the account * \li \c account is the \l Account object * \endlist * * \sa Account */ AccountModel::AccountModel(QObject *parent): QAbstractListModel(parent), d_ptr(new AccountModelPrivate(this)) { QObject::connect(this, SIGNAL(modelReset()), this, SIGNAL(countChanged())); QObject::connect(this, SIGNAL(rowsInserted(const QModelIndex &,int,int)), this, SIGNAL(countChanged())); QObject::connect(this, SIGNAL(rowsRemoved(const QModelIndex &,int,int)), this, SIGNAL(countChanged())); } AccountModel::~AccountModel() { delete d_ptr; } void AccountModel::classBegin() { } void AccountModel::componentComplete() { Q_D(AccountModel); d->update(); } /*! * \qmlproperty bool AccountModel::ready * * Whether the model is up to date: retrieving the account list is an * asynchronous operation, and therefore short delays are expected between * changing one model parameter and receiving the updated account list. * Applications should not rely on the model contents while this property is * false. */ bool AccountModel::isReady() const { Q_D(const AccountModel); return d->m_isReady; } /*! * \qmlproperty string AccountModel::applicationId * * The short application identifier (that is, the \c APP_ID minus the version * component) of the client. If not given, the identifier will be deduced from * the APP_ID environment variable. */ void AccountModel::setApplicationId(const QString &applicationId) { Q_D(AccountModel); if (applicationId == d->m_applicationId) return; d->m_applicationId = applicationId; d->m_applicationIdChanged = true; d->queueUpdate(); Q_EMIT applicationIdChanged(); } QString AccountModel::applicationId() const { Q_D(const AccountModel); return d->m_applicationId; } /*! * \qmlproperty string AccountModel::serviceId * * If this property is set, only accounts providing the given service will be * returned. */ void AccountModel::setServiceId(const QString &serviceId) { Q_D(AccountModel); if (serviceId == d->m_serviceId) return; d->m_serviceId = serviceId; d->m_serviceIdChanged = true; d->queueUpdate(); Q_EMIT serviceIdChanged(); } QString AccountModel::serviceId() const { Q_D(const AccountModel); return d->m_serviceId; } /*! * \qmlproperty list AccountModel::accountList * * List of accounts in the model. This list has exactly the same contents as * the model data, and is provided as a property just as a convenience for * those cases when a model is not required. */ QList AccountModel::accountList() const { Q_D(const AccountModel); QList objects; Q_FOREACH(Account *a, d->m_accounts) { objects.append(a); } return objects; } /*! * \qmlsignal AccountModel::accessReply(jsobject reply, jsobject authenticationData) * * Emitted when the request initiated with \l AccountModel::requestAccess() * completes. The \a reply object contains the access reply: * \list * \li \c account if access to an account was granted, this property will hold * an \l Account object * \li \c errorCode \l {errorCode} {error code}, if an error occurred * \li \c errorText is a textual description of the error, not meant for the * end-user; it can be used for debugging purposes * \endlist * * The second parameter, the \a authenticationData object, will contain the * authentication reply. */ /*! * \qmlmethod void AccountModel::requestAccess(string serviceId, * jsobject parameters) * * Requests the user to grant this application access to an account providing * the given service. The user will be asked whether this application should be * given access to the desired account; if no such accounts are currently * registered in the system, the user will be guided to create a new one. * * It should be noted that account authorizations persist across application * restart; therefore, this method should be called only when the application * needs a new account to appear in the model. * * Each call to this method will cause the \l accessReply signal to be * emitted at some time later. Note that the operation will involve * interactions with the end-user, so don't expect a reply to be emitted * immediately. * * The \a parameters parameter can be used to pass authentication data * (similarly to how the \l Account::authenticate() method works), if it's * desired to perform the authentication at the same time. * * \sa accessReply */ void AccountModel::requestAccess(const QString &service, const QVariantMap ¶meters) { Q_D(AccountModel); OnlineAccounts::PendingCall call = d->m_manager->requestAccess(service, authenticationDataFromMap(parameters)); OnlineAccounts::PendingCallWatcher *watcher = new OnlineAccounts::PendingCallWatcher(call, this); QObject::connect(watcher, SIGNAL(finished()), d, SLOT(onAccessRequestFinished())); } /*! * \qmlmethod variant AccountModel::get(int row, string roleName) * * Returns the data at \a row for the role \a roleName. */ QVariant AccountModel::get(int row, const QString &roleName) const { int role = roleNames().key(roleName.toLatin1(), -1); return data(index(row), role); } int AccountModel::rowCount(const QModelIndex &parent) const { Q_D(const AccountModel); Q_UNUSED(parent); return d->m_accounts.count(); } QVariant AccountModel::data(const QModelIndex &index, int role) const { Q_D(const AccountModel); int i = index.row(); if (i < 0 || i >= d->m_accounts.count()) return QVariant(); Account *account = d->m_accounts.at(i); QVariant ret; switch (role) { case Qt::DisplayRole: ret = QString("%1 - %2"). arg(account->displayName()). arg(account->serviceId()); break; case DisplayNameRole: ret = account->displayName(); break; case ValidRole: ret = account->isValid(); break; case AccountIdRole: ret = account->accountId(); break; case ServiceIdRole: ret = account->serviceId(); break; case AuthenticationMethodRole: ret = account->authenticationMethod(); break; case SettingsRole: ret = account->settings(); break; case AccountRole: ret = QVariant::fromValue(account); break; } return ret; } QHash AccountModel::roleNames() const { Q_D(const AccountModel); return d->roleNames; } #include "account_model.moc" online-accounts-api-0.1+16.04.20160212/src/lib/Ubuntu/OnlineAccounts.2/CMakeLists.txt0000644000015600001650000000260712657306726030246 0ustar pbuserpbgroup00000000000000project(OnlineAccountsQML) set(PLUGIN OnlineAccountsQML) include_directories(. ${CMAKE_CURRENT_BINARY_DIR} ${OnlineAccountsQt_SOURCE_DIR}/.. ) set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined") add_library(${PLUGIN} MODULE account.cpp account_model.cpp authentication_data.cpp plugin.cpp ) target_link_libraries(${PLUGIN} OnlineAccountsQt ) qt5_use_modules(${PLUGIN} Core Qml) set_target_properties(${PLUGIN} PROPERTIES AUTOMOC TRUE) file(GLOB QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml qmldir *.js) # Module install set(QT_INSTALL_QML "${CMAKE_INSTALL_LIBDIR}/qt5/qml") set(PLUGIN_IMPORTS_DIR "${QT_INSTALL_QML}/Ubuntu/OnlineAccounts.2") install(TARGETS ${PLUGIN} DESTINATION ${PLUGIN_IMPORTS_DIR}) install(FILES ${QML_FILES} DESTINATION ${PLUGIN_IMPORTS_DIR}) if(NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) # copy qml files over to build dir to be able to import them uninstalled foreach(_file ${QML_FILES}) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_file} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_file} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${_file} ${CMAKE_CURRENT_BINARY_DIR}/${_file}) endforeach(_file) add_custom_target(copy_files_to_build_dir DEPENDS ${QML_FILES}) add_dependencies(${PLUGIN} copy_files_to_build_dir) endif() online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/0000755000015600001650000000000012657307121024045 5ustar pbuserpbgroup00000000000000online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/pending_call.h0000644000015600001650000000375612657306726026662 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_PENDING_CALL_H #define ONLINE_ACCOUNTS_PENDING_CALL_H #include #include #include "global.h" namespace OnlineAccounts { class AuthenticationReplyPrivate; class ManagerPrivate; class PendingCallPrivate; class ONLINE_ACCOUNTS_EXPORT PendingCall { public: PendingCall(const PendingCall &other); ~PendingCall(); PendingCall &operator=(const PendingCall &other); bool isFinished() const; void waitForFinished(); protected: friend class PendingCallPrivate; friend class PendingCallWatcher; friend class AuthenticationReplyPrivate; friend class RequestAccessReplyPrivate; friend class ManagerPrivate; QExplicitlySharedDataPointer d; private: PendingCall(PendingCallPrivate *priv); }; class PendingCallWatcherPrivate; class ONLINE_ACCOUNTS_EXPORT PendingCallWatcher: public QObject, public PendingCall { Q_OBJECT public: PendingCallWatcher(const PendingCall &call, QObject *parent = 0); ~PendingCallWatcher(); Q_SIGNALS: void finished(); private: Q_DECLARE_PRIVATE(PendingCallWatcher) PendingCallWatcherPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_PENDING_CALL_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/authentication_data_p.h0000644000015600001650000000256612657306726030570 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_AUTHENTICATION_DATA_P_H #define ONLINE_ACCOUNTS_AUTHENTICATION_DATA_P_H #include "authentication_data.h" #include #include namespace OnlineAccounts { class AuthenticationDataPrivate: public QSharedData { public: inline AuthenticationDataPrivate(AuthenticationMethod method); virtual ~AuthenticationDataPrivate() {}; friend class AuthenticationData; AuthenticationMethod m_method; bool m_interactive; bool m_invalidateCachedReply; QVariantMap m_parameters; }; } // namespace #endif // ONLINE_ACCOUNTS_AUTHENTICATION_DATA_P_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/account.h0000644000015600001650000000342212657306726025665 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_ACCOUNT_H #define ONLINE_ACCOUNTS_ACCOUNT_H #include #include #include "global.h" #include "pending_call.h" namespace OnlineAccounts { class AuthenticationData; class Manager; class AccountPrivate; class ONLINE_ACCOUNTS_EXPORT Account: public QObject { Q_OBJECT public: ~Account(); /* Returns false if account deleted or disabled */ bool isValid() const; AccountId id() const; QString displayName() const; QString serviceId() const; AuthenticationMethod authenticationMethod() const; QStringList keys() const; QVariant setting(const QString &key) const; PendingCall authenticate(const AuthenticationData &authData); Q_SIGNALS: void changed(); void disabled(); protected: explicit Account(AccountPrivate *priv, QObject *parent); private: friend class Manager; friend class ManagerPrivate; Q_DECLARE_PRIVATE(Account) AccountPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_ACCOUNT_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/authentication_data.cpp0000644000015600001650000001250012657306732030566 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015-2016 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "authentication_data_p.h" #include #include "OnlineAccountsDaemon/dbus_constants.h" using namespace OnlineAccounts; AuthenticationDataPrivate::AuthenticationDataPrivate(AuthenticationMethod method): m_method(method), m_interactive(true), m_invalidateCachedReply(false) { } AuthenticationData::AuthenticationData(AuthenticationMethod method): d(new AuthenticationDataPrivate(method)) { } AuthenticationData::AuthenticationData(AuthenticationDataPrivate *priv): d(priv) { } AuthenticationData::AuthenticationData(const AuthenticationData &other): d(other.d) { } AuthenticationData::~AuthenticationData() { } AuthenticationMethod AuthenticationData::method() const { return d->m_method; } void AuthenticationData::setInteractive(bool interactive) { d->m_interactive = interactive; } bool AuthenticationData::interactive() const { return d->m_interactive; } void AuthenticationData::invalidateCachedReply() { d->m_invalidateCachedReply = true; } bool AuthenticationData::mustInvalidateCachedReply() const { return d->m_invalidateCachedReply; } void AuthenticationData::setParameters(const QVariantMap ¶meters) { d->m_parameters = parameters; } QVariantMap AuthenticationData::parameters() const { return d->m_parameters; } /* OAuth 2.0 */ OAuth2Data::OAuth2Data(): AuthenticationData(new AuthenticationDataPrivate(AuthenticationMethodOAuth2)) { qDBusRegisterMetaType>(); } void OAuth2Data::setClientId(const QByteArray &id) { d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_CLIENT_ID] = id; } QByteArray OAuth2Data::clientId() const { return d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_CLIENT_ID].toByteArray(); } void OAuth2Data::setClientSecret(const QByteArray &secret) { d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_CLIENT_SECRET] = secret; } QByteArray OAuth2Data::clientSecret() const { return d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_CLIENT_SECRET].toByteArray(); } void OAuth2Data::setScopes(const QList &scopes) { d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_SCOPES] = QVariant::fromValue(scopes); } QList OAuth2Data::scopes() const { return d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_SCOPES].value >(); } /* OAuth 1.0a */ OAuth1Data::OAuth1Data(): AuthenticationData(new AuthenticationDataPrivate(AuthenticationMethodOAuth1)) { } void OAuth1Data::setConsumerKey(const QByteArray &key) { d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_CONSUMER_KEY] = key; } QByteArray OAuth1Data::consumerKey() const { return d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_CONSUMER_KEY].toByteArray(); } void OAuth1Data::setConsumerSecret(const QByteArray &secret) { d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_CONSUMER_SECRET] = secret; } QByteArray OAuth1Data::consumerSecret() const { return d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_CONSUMER_SECRET].toByteArray(); } /* SASL */ SaslData::SaslData(): AuthenticationData(new AuthenticationDataPrivate(AuthenticationMethodSasl)) { } void SaslData::setService(const QString &service) { d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_SERVICE] = service; } QString SaslData::service() const { return d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_SERVICE].toString(); } void SaslData::setMechanismList(const QByteArray &mechanisms) { d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_MECHANISMS] = mechanisms; } QByteArray SaslData::mechanismList() const { return d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_MECHANISMS].toByteArray(); } void SaslData::setServerFqdn(const QString &fqdn) { d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_FQDN] = fqdn; } QString SaslData::serverFqdn() const { return d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_FQDN].toString(); } void SaslData::setLocalIp(const QString &localIp) { d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_LOCAL_IP] = localIp; } QString SaslData::localIp() const { return d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_LOCAL_IP].toString(); } void SaslData::setRemoteIp(const QString &remoteIp) { d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_REMOTE_IP] = remoteIp; } QString SaslData::remoteIp() const { return d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_REMOTE_IP].toString(); } void SaslData::setChallenge(const QByteArray &challenge) { d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_CHALLENGE] = challenge; } QByteArray SaslData::challenge() const { return d->m_parameters[ONLINE_ACCOUNTS_AUTH_KEY_CHALLENGE].toByteArray(); } /* Password */ PasswordData::PasswordData(): AuthenticationData(new AuthenticationDataPrivate(AuthenticationMethodPassword)) { } online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/account_info.cpp0000644000015600001650000000246012657306726027234 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "account_info.h" #include using namespace OnlineAccounts; namespace OnlineAccounts { QDBusArgument &operator<<(QDBusArgument &argument, const AccountInfo &info) { argument.beginStructure(); argument << info.accountId << info.details; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, AccountInfo &info) { argument.beginStructure(); argument >> info.accountId >> info.details; argument.endStructure(); return argument; } } online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/Account0000644000015600001650000000002512657306726025373 0ustar pbuserpbgroup00000000000000#include "account.h" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/AuthenticationReply0000644000015600001650000000004112657306726027770 0ustar pbuserpbgroup00000000000000#include "authentication_data.h" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/OAuth2Data0000644000015600001650000000004112657306726025671 0ustar pbuserpbgroup00000000000000#include "authentication_data.h" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/PendingCall0000644000015600001650000000003212657306726026155 0ustar pbuserpbgroup00000000000000#include "pending_call.h" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/account_p.h0000644000015600001650000000244112657306726026204 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_ACCOUNT_P_H #define ONLINE_ACCOUNTS_ACCOUNT_P_H #include "account.h" #include "account_info.h" namespace OnlineAccounts { class AccountPrivate { Q_DECLARE_PUBLIC(Account) public: AccountPrivate(Manager *manager, const AccountInfo &info); ~AccountPrivate(); void setInvalid(); void update(const AccountInfo &info); private: Manager *m_manager; AccountInfo m_info; bool m_isValid; mutable Account *q_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_ACCOUNT_P_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/Manager0000644000015600001650000000002512657306726025351 0ustar pbuserpbgroup00000000000000#include "manager.h" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/OnlineAccountsQt.pc.in0000644000015600001650000000045612657306726030246 0ustar pbuserpbgroup00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} libdir=${prefix}/@LIBDIR@ includedir=${prefix}/include Name: @CLIENT_LIB@ Description: Library for the simplified Online Accounts API Version: @PROJECT_VERSION@ Requires: Qt5Core Libs: -L${libdir} -l@CLIENT_LIB@ Cflags: -I${includedir}/@CLIENT_LIB@ online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/dbus_interface.cpp0000644000015600001650000000574512657306726027553 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "dbus_interface.h" #include #include #include using namespace OnlineAccounts; DBusInterface::DBusInterface(const QString &service, const QString &path, const char *interface, const QDBusConnection &connection, QObject *parent): QDBusAbstractInterface(service, path, interface, connection, parent) { setTimeout(INT_MAX); qDBusRegisterMetaType(); qDBusRegisterMetaType>(); bool ok = connect("AccountChanged", "s(ua{sv})", this, SLOT(onAccountChanged(const QString&,const OnlineAccounts::AccountInfo&))); if (Q_UNLIKELY(!ok)) { qCritical() << "Connection to AccountChanged signal failed"; } } DBusInterface::~DBusInterface() { } QDBusPendingCall DBusInterface::getAccounts(const QVariantMap &filters) { return asyncCall(QStringLiteral("GetAccounts"), filters); } QDBusPendingCall DBusInterface::authenticate(AccountId accountId, const QString &service, bool interactive, bool invalidate, const QVariantMap ¶meters) { return asyncCall(QStringLiteral("Authenticate"), accountId, service, interactive, invalidate, parameters); } QDBusPendingCall DBusInterface::requestAccess(const QString &service, const QVariantMap ¶meters) { return asyncCall(QStringLiteral("RequestAccess"), service, parameters); } void DBusInterface::onAccountChanged(const QString &service, const AccountInfo &info) { Q_EMIT accountChanged(service, info); } bool DBusInterface::connect(const char *signal, const char *signature, QObject *receiver, const char *slot) { return connection().connect(service(), path(), interface(), QLatin1String(signal), QLatin1String(signature), receiver, slot); } online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/dbus_interface.h0000644000015600001650000000433712657306726027214 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_DBUS_INTERFACE_H #define ONLINE_ACCOUNTS_DBUS_INTERFACE_H #include #include #include #include #include "account_info.h" namespace OnlineAccounts { /* Avoid using QDBusInterface which does a blocking introspection call. */ class DBusInterface: public QDBusAbstractInterface { Q_OBJECT public: DBusInterface(const QString &service, const QString &path, const char *interface, const QDBusConnection &connection, QObject *parent = 0); virtual ~DBusInterface(); QDBusPendingCall getAccounts(const QVariantMap &filters); QDBusPendingCall authenticate(AccountId accountId, const QString &service, bool interactive, bool invalidate, const QVariantMap ¶meters); QDBusPendingCall requestAccess(const QString &service, const QVariantMap ¶meters); Q_SIGNALS: void accountChanged(const QString &service, const OnlineAccounts::AccountInfo &info); private Q_SLOTS: void onAccountChanged(const QString &service, const OnlineAccounts::AccountInfo &info); private: bool connect(const char *signal, const char *signature, QObject *receiver, const char *slot); }; } #endif // ONLINE_ACCOUNTS_DBUS_INTERFACE_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/global.h0000644000015600001650000000245112657306732025467 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_GLOBAL_H #define ONLINE_ACCOUNTS_GLOBAL_H #include #if defined(BUILDING_ONLINE_ACCOUNTS) # define ONLINE_ACCOUNTS_EXPORT Q_DECL_EXPORT #else # define ONLINE_ACCOUNTS_EXPORT Q_DECL_IMPORT #endif namespace OnlineAccounts { typedef uint AccountId; enum AuthenticationMethod { AuthenticationMethodUnknown = 0, AuthenticationMethodOAuth1, AuthenticationMethodOAuth2, AuthenticationMethodPassword, AuthenticationMethodSasl, }; } // namespace #endif // ONLINE_ACCOUNTS_GLOBAL_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/manager_p.h0000644000015600001650000000410412657306726026160 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_MANAGER_P_H #define ONLINE_ACCOUNTS_MANAGER_P_H #include "manager.h" #include #include #include #include "account_info.h" #include "dbus_interface.h" class QDBusPendingCallWatcher; namespace OnlineAccounts { struct AccountData { AccountInfo info; QPointer account; AccountData(const AccountInfo &info): info(info) {} }; class ManagerPrivate: public QObject { Q_OBJECT Q_DECLARE_PUBLIC(Manager) public: inline ManagerPrivate(Manager *q, const QString &applicationId); ~ManagerPrivate(); PendingCall authenticate(const AccountInfo &info, const AuthenticationData &authData); PendingCall requestAccess(const QString &service, const QVariantMap ¶meters); Account *ensureAccount(const AccountInfo &info); private: void retrieveAccounts(); private Q_SLOTS: void onGetAccountsFinished(); void onAccountChanged(const QString &service, const OnlineAccounts::AccountInfo &info); private: QString m_applicationId; DBusInterface m_daemon; QDBusPendingCallWatcher *m_getAccountsCall; QHash m_accounts; mutable Manager *q_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_MANAGER_P_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/pending_call.cpp0000644000015600001650000000451312657306726027205 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "pending_call_p.h" #include using namespace OnlineAccounts; PendingCallPrivate::PendingCallPrivate(Manager *manager, const QDBusPendingCall &call, InvokedMethod method, AuthenticationMethod authMethod): m_manager(manager), m_call(call), m_invokedMethod(method), m_authenticationMethod(authMethod) { } PendingCall::PendingCall(PendingCallPrivate *priv): d(priv) { } PendingCall::PendingCall(const PendingCall &other): d(other.d) { } PendingCall::~PendingCall() { } PendingCall &PendingCall::operator=(const PendingCall &other) { d = other.d; return *this; } bool PendingCall::isFinished() const { return d->m_call.isFinished(); } void PendingCall::waitForFinished() { d->m_call.waitForFinished(); } namespace OnlineAccounts { class PendingCallWatcherPrivate { public: PendingCallWatcherPrivate(PendingCallWatcher *q); private: QDBusPendingCallWatcher m_watcher; }; } // namespace PendingCallWatcherPrivate::PendingCallWatcherPrivate(PendingCallWatcher *q): m_watcher(q->d->dbusCall()) { QObject::connect(&m_watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), q, SIGNAL(finished())); } PendingCallWatcher::PendingCallWatcher(const PendingCall &call, QObject *parent): QObject(parent), PendingCall(call), d_ptr(new PendingCallWatcherPrivate(this)) { } PendingCallWatcher::~PendingCallWatcher() { } online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/AuthenticationData0000644000015600001650000000004112657306726027546 0ustar pbuserpbgroup00000000000000#include "authentication_data.h" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/account.cpp0000644000015600001650000000455512657306726026230 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "account_p.h" #include "manager_p.h" using namespace OnlineAccounts; AccountPrivate::AccountPrivate(Manager *manager, const AccountInfo &info): m_manager(manager), m_info(info), m_isValid(true), q_ptr(0) { } AccountPrivate::~AccountPrivate() { } void AccountPrivate::setInvalid() { Q_Q(Account); m_isValid = false; Q_EMIT q->disabled(); } void AccountPrivate::update(const AccountInfo &info) { Q_Q(Account); if (info != m_info) { m_info = info; Q_EMIT q->changed(); } } Account::Account(AccountPrivate *priv, QObject *parent): QObject(parent), d_ptr(priv) { priv->q_ptr = this; } Account::~Account() { delete d_ptr; d_ptr = 0; } bool Account::isValid() const { Q_D(const Account); return d->m_isValid; } AccountId Account::id() const { Q_D(const Account); return d->m_info.id(); } QString Account::displayName() const { Q_D(const Account); return d->m_info.displayName(); } QString Account::serviceId() const { Q_D(const Account); return d->m_info.service(); } AuthenticationMethod Account::authenticationMethod() const { Q_D(const Account); return d->m_info.authenticationMethod(); } QStringList Account::keys() const { Q_D(const Account); return d->m_info.keys(); } QVariant Account::setting(const QString &key) const { Q_D(const Account); return d->m_info.setting(key); } PendingCall Account::authenticate(const AuthenticationData &authData) { Q_D(Account); ManagerPrivate *mPriv = d->m_manager->d_ptr; return mPriv->authenticate(d->m_info, authData); } online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/error.h0000644000015600001650000000316312657306726025364 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_ERROR_H #define ONLINE_ACCOUNTS_ERROR_H #include #include "global.h" namespace OnlineAccounts { class ONLINE_ACCOUNTS_EXPORT Error { public: enum Code { NoError = 0, NoAccount, /* Account got removed or disabled */ WrongType, /* For instance, using a PasswordReply to handle an OAuth reply */ UserCanceled, /* The user dismissed the authentication prompt */ PermissionDenied, InteractionRequired, }; Error(): m_code(NoError) {} Error(Code code, const QString &text): m_code(code), m_text(text) {} bool isValid() const { return m_code != NoError; } Code code() const { return m_code; } QString text() const { return m_text; } private: Code m_code; QString m_text; }; } // namespace #endif // ONLINE_ACCOUNTS_ERROR_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/error_p.h0000644000015600001650000000200112657306726025671 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_ERROR_P_H #define ONLINE_ACCOUNTS_ERROR_P_H #include "error.h" class QDBusError; namespace OnlineAccounts { Error errorFromDBus(const QDBusError &dbusError); } // namespace #endif // ONLINE_ACCOUNTS_ERROR_P_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/OAuth1Data0000644000015600001650000000004112657306726025670 0ustar pbuserpbgroup00000000000000#include "authentication_data.h" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/authentication_reply.cpp0000644000015600001650000002001112657306732031004 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015-2016 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "authentication_data.h" #include #include #include #include "OnlineAccountsDaemon/dbus_constants.h" #include "error_p.h" #include "pending_call_p.h" using namespace OnlineAccounts; static QVariant expandDBusArguments(const QVariant &variant) { if (variant.userType() == qMetaTypeId()) { QDBusArgument argument = variant.value(); if (argument.currentType() == QDBusArgument::MapType) { /* Assume that all maps are a{sv} */ QVariantMap map = qdbus_cast(argument); QVariantMap expandedMap; QMapIterator it(map); while (it.hasNext()) { it.next(); expandedMap.insert(it.key(), expandDBusArguments(it.value())); } return expandedMap; } else if (argument.currentType() == QDBusArgument::ArrayType) { if (argument.currentSignature() == "aay") { QList arrayList; argument >> arrayList; return QVariant::fromValue(arrayList); } else { /* We don't know how to handle other types */ qWarning() << "unhandled type" << argument.currentSignature(); return argument.asVariant(); } } else { /* We don't know how to handle other types */ return argument.asVariant(); } } else { return variant; } } namespace OnlineAccounts { class AuthenticationReplyPrivate { public: inline AuthenticationReplyPrivate(AuthenticationMethod method, const PendingCall &call); virtual ~AuthenticationReplyPrivate() {}; void setError(const Error &error) { m_error = error; } const QVariantMap &data() const { return m_replyData; } private: friend class AuthenticationReply; AuthenticationMethod m_authenticationMethod; PendingCall m_pendingCall; Error m_error; QVariantMap m_replyData; }; class OAuth2ReplyPrivate: public AuthenticationReplyPrivate { }; class OAuth1ReplyPrivate: public AuthenticationReplyPrivate { }; class SaslReplyPrivate: public AuthenticationReplyPrivate { }; class PasswordReplyPrivate: public AuthenticationReplyPrivate { }; } // namespace AuthenticationReplyPrivate::AuthenticationReplyPrivate(AuthenticationMethod method, const PendingCall &call): m_authenticationMethod(method), m_pendingCall(call) { const PendingCallPrivate *pCall = call.d.constData(); if (m_authenticationMethod != AuthenticationMethodUnknown && pCall->authenticationMethod() != AuthenticationMethodUnknown && m_authenticationMethod != pCall->authenticationMethod()) { setError(Error(Error::WrongType, "Authentication method mismatch")); return; } if (!m_pendingCall.isFinished()) { m_pendingCall.waitForFinished(); } if (Q_UNLIKELY(pCall->dbusCall().isError())) { setError(errorFromDBus(pCall->dbusCall().error())); return; } QDBusMessage msg = pCall->dbusCall().reply(); PendingCallPrivate::InvokedMethod invokedMethod = pCall->invokedMethod(); if (invokedMethod == PendingCallPrivate::Authenticate) { m_replyData = expandDBusArguments(msg.arguments().at(0)).toMap(); } else if (invokedMethod == PendingCallPrivate::RequestAccess) { m_replyData = expandDBusArguments(msg.arguments().at(1)).toMap(); } else { qFatal("Unknown invoked method %d", invokedMethod); } qDebug() << "reply data:" << m_replyData; } AuthenticationReply::AuthenticationReply(const PendingCall &call): d_ptr(new AuthenticationReplyPrivate(AuthenticationMethodUnknown, call)) { } AuthenticationReply::AuthenticationReply(AuthenticationReplyPrivate *priv): d_ptr(priv) { } AuthenticationReply::~AuthenticationReply() { delete d_ptr; } Error AuthenticationReply::error() const { Q_D(const AuthenticationReply); return d->m_error; } QVariantMap AuthenticationReply::data() const { Q_D(const AuthenticationReply); return d->data(); } /* OAuth 2.0 */ OAuth2Reply::OAuth2Reply(const PendingCall &call): AuthenticationReply(new AuthenticationReplyPrivate(AuthenticationMethodOAuth2, call)) { } OAuth2Reply::~OAuth2Reply() { } QByteArray OAuth2Reply::accessToken() const { Q_D(const AuthenticationReply); return d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_ACCESS_TOKEN).toByteArray(); } int OAuth2Reply::expiresIn() const { Q_D(const AuthenticationReply); return d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_EXPIRES_IN).toInt(); } QList OAuth2Reply::grantedScopes() const { Q_D(const AuthenticationReply); return d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_GRANTED_SCOPES).value >(); } /* OAuth 1.0a */ OAuth1Reply::OAuth1Reply(const PendingCall &call): AuthenticationReply(new AuthenticationReplyPrivate(AuthenticationMethodOAuth1, call)) { } OAuth1Reply::~OAuth1Reply() { } QByteArray OAuth1Reply::consumerKey() const { Q_D(const AuthenticationReply); return d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_CONSUMER_KEY).toByteArray(); } QByteArray OAuth1Reply::consumerSecret() const { Q_D(const AuthenticationReply); return d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_CONSUMER_SECRET).toByteArray(); } QByteArray OAuth1Reply::token() const { Q_D(const AuthenticationReply); return d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_TOKEN).toByteArray(); } QByteArray OAuth1Reply::tokenSecret() const { Q_D(const AuthenticationReply); return d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_TOKEN_SECRET).toByteArray(); } QByteArray OAuth1Reply::signatureMethod() const { Q_D(const AuthenticationReply); return d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_SIGNATURE_METHOD).toByteArray(); } /* SASL */ SaslReply::SaslReply(const PendingCall &call): AuthenticationReply(new AuthenticationReplyPrivate(AuthenticationMethodSasl, call)) { } SaslReply::~SaslReply() { } QString SaslReply::chosenMechanism() const { Q_D(const AuthenticationReply); return d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_CHOSEN_MECHANISM).toString(); } QByteArray SaslReply::response() const { Q_D(const AuthenticationReply); return d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_RESPONSE).toByteArray(); } SaslReply::State SaslReply::state() const { Q_D(const AuthenticationReply); int state = d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_STATE).toInt(); switch (state) { case ONLINE_ACCOUNTS_AUTH_SASL_STATE_FINISHED: return Finished; case ONLINE_ACCOUNTS_AUTH_SASL_STATE_CONTINUE: return Continue; default: qWarning() << "Unknown SASL state" << state; return Finished; } } /* Password */ PasswordReply::PasswordReply(const PendingCall &call): AuthenticationReply(new AuthenticationReplyPrivate(AuthenticationMethodPassword, call)) { } PasswordReply::~PasswordReply() { } QByteArray PasswordReply::username() const { Q_D(const AuthenticationReply); return d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_USERNAME).toByteArray(); } QByteArray PasswordReply::password() const { Q_D(const AuthenticationReply); return d->data().value(ONLINE_ACCOUNTS_AUTH_KEY_PASSWORD).toByteArray(); } online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/authentication_data.h0000644000015600001650000001220712657306732030237 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015-2016 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_AUTHENTICATION_DATA_H #define ONLINE_ACCOUNTS_AUTHENTICATION_DATA_H #include #include #include #include "error.h" #include "global.h" #include "pending_call.h" namespace OnlineAccounts { class Manager; class AuthenticationDataPrivate; class ONLINE_ACCOUNTS_EXPORT AuthenticationData { public: AuthenticationData(AuthenticationMethod method); AuthenticationData(const AuthenticationData &other); virtual ~AuthenticationData(); AuthenticationMethod method() const; void setInteractive(bool interactive); bool interactive() const; void invalidateCachedReply(); bool mustInvalidateCachedReply() const; void setParameters(const QVariantMap ¶meters); QVariantMap parameters() const; protected: AuthenticationData(AuthenticationDataPrivate *priv); QSharedDataPointer d; private: friend class Manager; friend class ManagerPrivate; }; class AuthenticationReplyPrivate; class ONLINE_ACCOUNTS_EXPORT AuthenticationReply { public: AuthenticationReply(const PendingCall &call); virtual ~AuthenticationReply(); bool hasError() const { return error().isValid(); } Error error() const; QVariantMap data() const; protected: AuthenticationReply(AuthenticationReplyPrivate *priv); AuthenticationReplyPrivate *d_ptr; private: Q_DECLARE_PRIVATE(AuthenticationReply) Q_DISABLE_COPY(AuthenticationReply) }; /* OAuth 2.0 */ class ONLINE_ACCOUNTS_EXPORT OAuth2Data: public AuthenticationData { public: OAuth2Data(); void setClientId(const QByteArray &id); QByteArray clientId() const; void setClientSecret(const QByteArray &secret); QByteArray clientSecret() const; void setScopes(const QList &scopes); QList scopes() const; }; class OAuth2ReplyPrivate; class ONLINE_ACCOUNTS_EXPORT OAuth2Reply: public AuthenticationReply { public: OAuth2Reply(const PendingCall &call); ~OAuth2Reply(); QByteArray accessToken() const; int expiresIn() const; QList grantedScopes() const; private: Q_DECLARE_PRIVATE(OAuth2Reply) Q_DISABLE_COPY(OAuth2Reply) }; /* OAuth 1.0a */ class ONLINE_ACCOUNTS_EXPORT OAuth1Data: public AuthenticationData { public: OAuth1Data(); void setConsumerKey(const QByteArray &consumerKey); QByteArray consumerKey() const; void setConsumerSecret(const QByteArray &consumerSecret); QByteArray consumerSecret() const; }; class OAuth1ReplyPrivate; class ONLINE_ACCOUNTS_EXPORT OAuth1Reply: public AuthenticationReply { public: OAuth1Reply(const PendingCall &call); ~OAuth1Reply(); QByteArray consumerKey() const; QByteArray consumerSecret() const; QByteArray token() const; QByteArray tokenSecret() const; QByteArray signatureMethod() const; private: Q_DECLARE_PRIVATE(OAuth1Reply) Q_DISABLE_COPY(OAuth1Reply) }; /* SASL */ class ONLINE_ACCOUNTS_EXPORT SaslData: public AuthenticationData { public: SaslData(); void setService(const QString &service); QString service() const; void setMechanismList(const QByteArray &mechanisms); QByteArray mechanismList() const; void setServerFqdn(const QString &fqdn); QString serverFqdn() const; void setLocalIp(const QString &localIp); QString localIp() const; void setRemoteIp(const QString &remoteIp); QString remoteIp() const; void setChallenge(const QByteArray &challenge); QByteArray challenge() const; }; class SaslReplyPrivate; class ONLINE_ACCOUNTS_EXPORT SaslReply: public AuthenticationReply { public: enum State { Finished, Continue, }; SaslReply(const PendingCall &call); ~SaslReply(); QString chosenMechanism() const; QByteArray response() const; State state() const; private: Q_DECLARE_PRIVATE(SaslReply) Q_DISABLE_COPY(SaslReply) }; /* Password */ class ONLINE_ACCOUNTS_EXPORT PasswordData: public AuthenticationData { public: PasswordData(); }; class PasswordReplyPrivate; class ONLINE_ACCOUNTS_EXPORT PasswordReply: public AuthenticationReply { public: PasswordReply(const PendingCall &call); ~PasswordReply(); QByteArray username() const; QByteArray password() const; private: Q_DECLARE_PRIVATE(PasswordReply) Q_DISABLE_COPY(PasswordReply) }; } // namespace #endif // ONLINE_ACCOUNTS_AUTHENTICATION_DATA_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/pending_call_p.h0000644000015600001650000000351612657306726027173 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_PENDING_CALL_P_H #define ONLINE_ACCOUNTS_PENDING_CALL_P_H #include "pending_call.h" #include #include namespace OnlineAccounts { class Manager; class PendingCallPrivate: public QSharedData { public: enum InvokedMethod { Authenticate, RequestAccess, }; PendingCallPrivate(Manager *manager, const QDBusPendingCall &call, InvokedMethod method, AuthenticationMethod authMethod); ~PendingCallPrivate() {}; Manager *manager() const { return m_manager; } QDBusPendingCall dbusCall() const { return m_call; } InvokedMethod invokedMethod() const { return m_invokedMethod; } AuthenticationMethod authenticationMethod() const { return m_authenticationMethod; } private: friend class PendingCall; Manager *m_manager; QDBusPendingCall m_call; InvokedMethod m_invokedMethod; AuthenticationMethod m_authenticationMethod; }; } // namespace #endif // ONLINE_ACCOUNTS_PENDING_CALL_P_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/error.cpp0000644000015600001650000000260012657306726025712 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "error_p.h" #include #include "OnlineAccountsDaemon/dbus_constants.h" namespace OnlineAccounts { Error errorFromDBus(const QDBusError &dbusError) { Error::Code code = Error::PermissionDenied; QString name = dbusError.name(); if (name == ONLINE_ACCOUNTS_ERROR_NO_ACCOUNT) { code = Error::NoAccount; } else if (name == ONLINE_ACCOUNTS_ERROR_USER_CANCELED) { code = Error::UserCanceled; } else if (name == ONLINE_ACCOUNTS_ERROR_INTERACTION_REQUIRED) { code = Error::InteractionRequired; } return Error(code, dbusError.message()); } } // namespace online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/request_access_reply.cpp0000644000015600001650000000527612657306726031021 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "manager_p.h" #include #include #include #include "pending_call_p.h" using namespace OnlineAccounts; namespace OnlineAccounts { class RequestAccessReplyPrivate { public: inline RequestAccessReplyPrivate(const PendingCall &call); virtual ~RequestAccessReplyPrivate() {} Account *account(); private: friend class RequestAccessReply; PendingCall m_pendingCall; AccountInfo m_accountInfo; Error m_error; }; } // namespace RequestAccessReplyPrivate::RequestAccessReplyPrivate(const PendingCall &call): m_pendingCall(call) { const PendingCallPrivate *pCall = call.d.constData(); if (!m_pendingCall.isFinished()) { m_pendingCall.waitForFinished(); } if (Q_UNLIKELY(pCall->dbusCall().isError())) { /* Treat all errors as permission denied. */ qWarning() << "Error:" << pCall->dbusCall().error().message(); m_error = Error(Error::PermissionDenied, pCall->dbusCall().error().message()); return; } PendingCallPrivate::InvokedMethod invokedMethod = pCall->invokedMethod(); if (Q_UNLIKELY(invokedMethod != PendingCallPrivate::RequestAccess)) { qFatal("Wrong invoked method %d", invokedMethod); } QDBusPendingReply reply(pCall->dbusCall()); m_accountInfo = reply.argumentAt<0>(); } Account *RequestAccessReplyPrivate::account() { ManagerPrivate *managerPriv = m_pendingCall.d->manager()->d_ptr; return managerPriv->ensureAccount(m_accountInfo); } RequestAccessReply::RequestAccessReply(const PendingCall &call): d_ptr(new RequestAccessReplyPrivate(call)) { } RequestAccessReply::~RequestAccessReply() { delete d_ptr; } Error RequestAccessReply::error() const { Q_D(const RequestAccessReply); return d->m_error; } Account *RequestAccessReply::account() { Q_D(RequestAccessReply); return d->account(); } online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/account_info.h0000644000015600001650000000645612657306726026712 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_ACCOUNT_INFO_H #define ONLINE_ACCOUNTS_ACCOUNT_INFO_H #include #include "OnlineAccountsDaemon/dbus_constants.h" #include "global.h" class QDBusArgument; namespace OnlineAccounts { class AccountInfo { public: enum ChangeType { Enabled, Disabled, Updated, }; AccountInfo(): accountId(0) {} AccountInfo(AccountId accountId, const QVariantMap &details): accountId(accountId), details(details) {} AccountId id() const { return accountId; } QString displayName() const { return details.value(ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME).toString(); } QString service() const { return details.value(ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID).toString(); } AuthenticationMethod authenticationMethod() const { return AuthenticationMethod(details.value(ONLINE_ACCOUNTS_INFO_KEY_AUTH_METHOD).toInt()); } ChangeType changeType() const { switch (details.value(ONLINE_ACCOUNTS_INFO_KEY_CHANGE_TYPE).toUInt()) { case ONLINE_ACCOUNTS_INFO_CHANGE_ENABLED: return Enabled; case ONLINE_ACCOUNTS_INFO_CHANGE_DISABLED: return Disabled; default: return Updated; } } QStringList keys() const { QStringList settingKeys; Q_FOREACH(const QString &key, details.keys()) { if (key.startsWith(ONLINE_ACCOUNTS_INFO_KEY_SETTINGS)) { settingKeys.append(key.mid(sizeof(ONLINE_ACCOUNTS_INFO_KEY_SETTINGS) - 1)); } } return settingKeys; } QVariant setting(const QString &key) const { return details.value(ONLINE_ACCOUNTS_INFO_KEY_SETTINGS + key); } AccountInfo stripMetadata() const { AccountInfo stripped = *this; stripped.details.remove(ONLINE_ACCOUNTS_INFO_KEY_CHANGE_TYPE); return stripped; } bool operator==(const AccountInfo &other) const { return accountId == other.accountId && details == other.details; } bool operator!=(const AccountInfo &other) const { return !(*this == other); } private: friend QDBusArgument &operator<<(QDBusArgument &, const AccountInfo &); friend const QDBusArgument &operator>>(const QDBusArgument &, AccountInfo &); AccountId accountId; QVariantMap details; }; QDBusArgument &operator<<(QDBusArgument &argument, const AccountInfo &info); const QDBusArgument &operator>>(const QDBusArgument &argument, AccountInfo &info); } //namespace Q_DECLARE_METATYPE(OnlineAccounts::AccountInfo) #endif // ONLINE_ACCOUNTS_ACCOUNT_INFO_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/Error0000644000015600001650000000002312657306726025066 0ustar pbuserpbgroup00000000000000#include "error.h" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/CMakeLists.txt0000644000015600001650000000235512657306726026624 0ustar pbuserpbgroup00000000000000project(OnlineAccountsQt) set(CLIENT_LIB OnlineAccountsQt) include_directories(. ${CMAKE_CURRENT_BINARY_DIR} ${OnlineAccountsDaemon_SOURCE_DIR}/.. ) set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") set(CMAKE_CXX_VISIBILITY_PRESET hidden) add_library(${CLIENT_LIB} SHARED account.cpp account_info.cpp authentication_data.cpp authentication_reply.cpp dbus_interface.cpp error.cpp manager.cpp pending_call.cpp request_access_reply.cpp ) set_target_properties(${CLIENT_LIB} PROPERTIES VERSION 1.0.0 SOVERSION 1 ) qt5_use_modules(${CLIENT_LIB} DBus) set_target_properties(${CLIENT_LIB} PROPERTIES AUTOMOC TRUE) # Library install install(TARGETS ${CLIENT_LIB} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) # Development files configure_file(${CLIENT_LIB}.pc.in ${CLIENT_LIB}.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CLIENT_LIB}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(FILES Account account.h AuthenticationData authentication_data.h AuthenticationReply Error error.h global.h Manager manager.h OAuth1Data OAuth2Data PasswordData PendingCall pending_call.h PendingCallWatcher DESTINATION include/${CLIENT_LIB}/OnlineAccounts ) online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/PasswordData0000644000015600001650000000004112657306726026371 0ustar pbuserpbgroup00000000000000#include "authentication_data.h" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/manager.cpp0000644000015600001650000001614712657306726026206 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "manager_p.h" #include #include #include #include #include "account_p.h" #include "authentication_data_p.h" #include "OnlineAccountsDaemon/dbus_constants.h" #include "pending_call_p.h" using namespace OnlineAccounts; ManagerPrivate::ManagerPrivate(Manager *q, const QString &applicationId): QObject(), m_applicationId(applicationId), m_daemon(ONLINE_ACCOUNTS_MANAGER_SERVICE_NAME, ONLINE_ACCOUNTS_MANAGER_PATH, ONLINE_ACCOUNTS_MANAGER_INTERFACE, QDBusConnection::sessionBus()), m_getAccountsCall(0), q_ptr(q) { qRegisterMetaType(); QObject::connect(&m_daemon, SIGNAL(accountChanged(const QString&, const OnlineAccounts::AccountInfo&)), this, SLOT(onAccountChanged(const QString&, const OnlineAccounts::AccountInfo&))); retrieveAccounts(); } ManagerPrivate::~ManagerPrivate() { delete m_getAccountsCall; m_getAccountsCall = 0; } PendingCall ManagerPrivate::authenticate(const AccountInfo &info, const AuthenticationData &authData) { Q_Q(Manager); QDBusPendingCall call = m_daemon.authenticate(info.id(), info.service(), authData.interactive(), authData.mustInvalidateCachedReply(), authData.d->m_parameters); return PendingCall(new PendingCallPrivate(q, call, PendingCallPrivate::Authenticate, authData.method())); } PendingCall ManagerPrivate::requestAccess(const QString &service, const QVariantMap ¶meters) { Q_Q(Manager); QDBusPendingCall call = m_daemon.requestAccess(service, parameters); return PendingCall(new PendingCallPrivate(q, call, PendingCallPrivate::RequestAccess, AuthenticationMethodUnknown)); } Account *ManagerPrivate::ensureAccount(const AccountInfo &info) { if (Q_UNLIKELY(info.id() == 0)) return 0; QHash::iterator i = m_accounts.find(info.id()); if (i == m_accounts.end()) { i = m_accounts.insert(info.id(), AccountData(info)); } AccountData &accountData = i.value(); accountData.info = info.stripMetadata(); if (!accountData.account) { accountData.account = new Account(new AccountPrivate(q_ptr, accountData.info), this); } else { /* Update the account information */ accountData.account->d_ptr->update(accountData.info); } return accountData.account; } void ManagerPrivate::retrieveAccounts() { if (Q_UNLIKELY(m_getAccountsCall)) return; QVariantMap filters; filters["applicationId"] = m_applicationId; m_getAccountsCall = new QDBusPendingCallWatcher(m_daemon.getAccounts(filters)); QObject::connect(m_getAccountsCall, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onGetAccountsFinished())); } void ManagerPrivate::onGetAccountsFinished() { Q_Q(Manager); Q_ASSERT(m_getAccountsCall); QDBusPendingReply > reply = *m_getAccountsCall; if (Q_UNLIKELY(reply.isError())) { qWarning() << "GetAccounts call failed:" << reply.error(); /* No special handling of the error: the Manager will simply not have * any account */ } else { QList accountInfos = reply.argumentAt<0>(); Q_FOREACH(const AccountInfo &info, accountInfos) { m_accounts.insert(info.id(), AccountData(info)); } } m_getAccountsCall->deleteLater(); m_getAccountsCall = 0; Q_EMIT q->ready(); } void ManagerPrivate::onAccountChanged(const QString &service, const AccountInfo &info) { Q_Q(Manager); Q_UNUSED(service); Account *account = ensureAccount(info); if (info.changeType() == AccountInfo::Enabled) { Q_EMIT q->accountAvailable(account); } else if (info.changeType() == AccountInfo::Disabled) { account->d_ptr->setInvalid(); /* We don't delete the account, since the client might be using it, but * we remove it from our list so that we won't return it to the client * anymore. */ m_accounts.remove(info.id()); } /* No need to handle the Update change type: ensureAccount already updates * the account and emits the necessary notification */ } Manager::Manager(const QString &applicationId, QObject *parent): QObject(parent), d_ptr(new ManagerPrivate(this, applicationId)) { } Manager::~Manager() { delete d_ptr; d_ptr = 0; } bool Manager::isReady() const { Q_D(const Manager); return !d->m_getAccountsCall; } void Manager::waitForReady() { Q_D(Manager); if (d->m_getAccountsCall) { d->m_getAccountsCall->waitForFinished(); } } QList Manager::availableAccounts(const QString &service) { Q_D(Manager); QList result; for (QHash::iterator i = d->m_accounts.begin(); i != d->m_accounts.end(); i++) { AccountData &accountData = i.value(); if (!service.isEmpty() && accountData.info.service() != service) continue; if (!accountData.account) { accountData.account = new Account(new AccountPrivate(this, accountData.info), this); } result.append(accountData.account); } return result; } Account *Manager::account(AccountId accountId) { Q_D(Manager); QHash::iterator i = d->m_accounts.find(accountId); if (Q_UNLIKELY(i == d->m_accounts.end())) return 0; AccountData &accountData = i.value(); if (!accountData.account) { accountData.account = new Account(new AccountPrivate(this, accountData.info), this); } return accountData.account; } PendingCall Manager::requestAccess(const QString &service, const AuthenticationData &authData) { Q_D(Manager); return d->requestAccess(service, authData.d->m_parameters); } online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/manager.h0000644000015600001650000000427512657306726025652 0ustar pbuserpbgroup00000000000000/* * This file is part of libOnlineAccounts * * Copyright (C) 2015 Canonical Ltd. * * Contact: Alberto Mardegan * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ONLINE_ACCOUNTS_MANAGER_H #define ONLINE_ACCOUNTS_MANAGER_H #include #include #include "error.h" #include "global.h" #include "pending_call.h" namespace OnlineAccounts { class Account; class AuthenticationData; class RequestAccessReplyPrivate; class ManagerPrivate; class ONLINE_ACCOUNTS_EXPORT Manager: public QObject { Q_OBJECT public: explicit Manager(const QString &applicationId, QObject *parent = 0); ~Manager(); bool isReady() const; void waitForReady(); QList availableAccounts(const QString &service = QString()); Account *account(AccountId accountId); PendingCall requestAccess(const QString &service, const AuthenticationData &authData); Q_SIGNALS: void ready(); void accountAvailable(OnlineAccounts::Account *account); private: friend class Account; friend class RequestAccessReplyPrivate; Q_DECLARE_PRIVATE(Manager) Q_DISABLE_COPY(Manager) ManagerPrivate *d_ptr; }; class ONLINE_ACCOUNTS_EXPORT RequestAccessReply { public: RequestAccessReply(const PendingCall &call); virtual ~RequestAccessReply(); bool hasError() const { return error().isValid(); } Error error() const; Account *account(); private: Q_DECLARE_PRIVATE(RequestAccessReply) Q_DISABLE_COPY(RequestAccessReply) RequestAccessReplyPrivate *d_ptr; }; } // namespace #endif // ONLINE_ACCOUNTS_MANAGER_H online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/SaslData0000644000015600001650000000004112657306732025466 0ustar pbuserpbgroup00000000000000#include "authentication_data.h" online-accounts-api-0.1+16.04.20160212/src/lib/OnlineAccounts/PendingCallWatcher0000644000015600001650000000003212657306726027473 0ustar pbuserpbgroup00000000000000#include "pending_call.h" online-accounts-api-0.1+16.04.20160212/CMakeLists.txt0000644000015600001650000000305212657306726022336 0ustar pbuserpbgroup00000000000000cmake_minimum_required(VERSION 3.0) project(OnlineAccountsApi CXX) set(PROJECT_VERSION 0.1) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" "${CMAKE_MODULE_PATH}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Wextra -std=c++11") string(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type_lower) # Build types should always be lowercase but sometimes they are not. include(GNUInstallDirs) include(FindPkgConfig) find_package(Qt5Core REQUIRED) find_package(Qt5DBus REQUIRED) pkg_check_modules(APPARMOR libapparmor REQUIRED) set(CMAKE_AUTOMOC ON) add_subdirectory(src/lib/OnlineAccountsDaemon) add_subdirectory(src/daemon) add_subdirectory(src/lib/OnlineAccounts) add_subdirectory(src/lib/Ubuntu/OnlineAccounts.2) add_subdirectory(doc) if(cmake_build_type_lower MATCHES coverage) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage" ) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage" ) set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} --coverage" ) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --coverage" ) # We add -g when building with coverage so valgrind reports line numbers. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g" ) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g" ) endif() enable_testing() add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) add_subdirectory(tests) include(EnableCoverageReport) if(cmake_build_type_lower MATCHES coverage) ENABLE_COVERAGE_REPORT(TARGETS OnlineAccountsQt OnlineAccountsQML accountd FILTER /usr/include ${CMAKE_SOURCE_DIR}/tests/* ${CMAKE_BINARY_DIR}/*) endif()